Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

25 Essential Python Programming Exercises: From Mathematical Puzzles to Classic Algorithms

Tech May 14 2

Problem 1: Narcissistic Numbers (Armstrong Numbers)

A Narcissistic number (also known as an Armstrong number or PPDI) is a 3-digit number where the sum of the cubes of its digits equals the number itself. For example: $1^3 + 5^3 + 3^3 = 153$.

for candidate in range(100, 1000):
    hundreds = candidate // 100
    tens = (candidate // 10) % 10
    units = candidate % 10
    
    if hundreds ** 3 + tens ** 3 + units ** 3 == candidate:
        print(f"{candidate} is a Narcissistic number")
        # Output: 153, 370, 371, 407

Problem 2: Four-Leaf Rose Numbers

These are 4-digit numbers where the sum of the fourth powers of each digit equals the number itself. This extends the concept of Narcissistic numbers to 4 digits.

for num in range(1000, 10000):
    d1 = num // 1000
    d2 = (num // 100) % 10
    d3 = (num // 10) % 10
    d4 = num % 10
    
    if d1 ** 4 + d2 ** 4 + d3 ** 4 + d4 ** 4 == num:
        print(f"{num} is a Four-Leaf Rose number")
        # Output: 1634, 8208, 9474

Problem 3: Reverse String Output

Method 1: Slicing

text = input("Enter a string: ")
print(text[::-1])

Method 2: Loop Construction

text = input("Enter a string: ")
chars = []
for idx in range(len(text) - 1, -1, -1):
    chars.append(text[idx])
print(''.join(chars))

Problem 4: Number Guessing Game

Generate a random integer between 0 and 100. The player has 10 attempts to guess the number with hints indicating if the guess is too high or too low.

import random

target = random.randint(0, 100)
max_attempts = 10

for attempt in range(max_attempts):
    guess = int(input("Enter your guess: "))
    
    if guess > target:
        print("Too high!")
    elif guess < target:
        print("Too low!")
    else:
        print(f"Correct! You won in {attempt + 1} attempts.")
        break
    
    print(f"Remaining attempts: {max_attempts - attempt - 1}")
else:
    print("Game over. You ran out of attempts.")

Problem 5: Hundred Chickens Problem

A classic Chinese mathematical puzzle: With 100 yuan, buy exactly 100 chickens. Roosters cost 5 yuan each, hens cost 3 yuan each, and chicks cost 1 yuan for 3. All three types must be purchased.

Mathematical Model:

  • $x + y + z = 100$ (total chickens)
  • $5x + 3y + z/3 = 100$ (total cost)
solutions = 0
for roosters in range(1, 20):  # Max 20 roosters (5*20=100)
    for hens in range(1, 34):  # Max 33 hens (3*33=99)
        chicks = 100 - roosters - hens
        if chicks > 0 and 5 * roosters + 3 * hens + chicks / 3 == 100:
            solutions += 1
            print(f"Solution {solutions}: {roosters} roosters, {hens} hens, {chicks} chicks")

Problem 6: Advanced Leap Year Calculation

Input a year, month, and day. Determine if it's a leap year and calculate the day of the year.

Leap Year Rules:

  • Divisible by 4 but not by 100, OR
  • Divisible by 400
year = int(input("Enter year: "))
month = int(input("Enter month: "))
day = int(input("Enter day: "))

month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

# Check leap year
if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
    print(f"{year} is a leap year")
    month_days[1] = 29
else:
    print(f"{year} is not a leap year")

# Calculate day of year
day_count = day
for m in range(month - 1):
    day_count += month_days[m]

print(f"{year}-{month:02d}-{day:02d} is day {day_count} of the year")

Problem 7: Monkey and Peaches

A monkey picks peaches. On day 1, it eats half plus one more. This pattern continues each morning. On the morning of day 10, only 1 peach remains. How many were picked originally?

Approach: Work backwards from day 10.

peaches = 1
print(f"Day 10 morning: {peaches} peach(es)")

for day in range(9, 0, -1):
    peaches = (peaches + 1) * 2
    print(f"Day {day} morning: {peaches} peach(es)")

print(f"\nOriginal count: {peaches} peaches")

Problem 8: Bubble Sort

Bubble sort repeatedly steps through the list, compares adjacent elements, and swaps them if they are in the wrong order. Larger elements "bubble up" to the end.

import numpy as np

data = np.random.randint(100, size=6)
n = len(data)

print(f"Original: {data}")

for outer in range(n - 1):
    for inner in range(n - outer - 1):
        if data[inner] > data[inner + 1]:
            data[inner], data[inner + 1] = data[inner + 1], data[inner]

print(f"Sorted: {data}")

Problem 9: Binary Search

Binary search efficiently locates a target value in a sorted array by repeatedly dividing the search interval in half.

Method 1: Iterative

def binary_search_iterative(sorted_arr, target):
    low, high = 0, len(sorted_arr) - 1
    iterations = 0
    
    while low <= high:
        mid = (low + high) // 2
        iterations += 1
        
        if target > sorted_arr[mid]:
            low = mid + 1
        elif target < sorted_arr[mid]:
            high = mid - 1
        else:
            print(f"Found {target} at index {mid} in {iterations} iterations")
            return mid
    
    print(f"{target} not found")
    return -1

binary_search_iterative([5, 7, 11, 22, 27, 33, 39, 52, 58], 11)

Method 2: Recursive

def binary_search_recursive(sorted_arr, target, low, high):
    if low > high:
        return -1
    
    mid = (low + high) // 2
    
    if target < sorted_arr[mid]:
        return binary_search_recursive(sorted_arr, target, low, mid - 1)
    elif target > sorted_arr[mid]:
        return binary_search_recursive(sorted_arr, target, mid + 1, high)
    else:
        return mid

print(binary_search_recursive([5, 7, 11, 22, 27, 33, 39, 52, 58], 11, 0, 8))

Problem 10: Selection Sort

Selection sort divides the list into a sorted portion (left) and unsorted portion (right). It repeatedly finds the minimum element from the unsorted portion and moves it to the end of the sorted portion.

import random

values = [random.randint(1, 100) for _ in range(8)]
size = len(values)

print(f"Unsorted: {values}")

for current in range(size - 1):
    min_pos = current
    for comparison in range(current + 1, size):
        if values[min_pos] > values[comparison]:
            min_pos = comparison
    values[current], values[min_pos] = values[min_pos], values[current]
    print(f"After round {current + 1}: {values}")

print(f"Final sorted: {values}")

Problem 11: Rock Paper Scissors Game

Players start with 100 points. Winning adds 10 points, losing subtracts 10. Reach 200 to win, drop to 0 to lose.

  • 1 = Scissors
  • 2 = Rock
  • 3 = Paper
import random

choices = {1: "Scissors", 2: "Rock", 3: "Paper"}
player_score = 100

print("Rock Paper Scissors - Start with 100 points")
print("Reach 200 to win, 0 to lose")

while True:
    computer_move = random.randint(1, 3)
    player_input = input("Your choice (1-3): ")
    
    if player_input not in '123':
        print("Invalid choice")
        continue
    
    player_move = int(player_input)
    print(f"Computer: {choices[computer_move]}, You: {choices[player_move]}")
    
    if (player_move == 1 and computer_move == 3) or \
       (player_move == 2 and computer_move == 1) or \
       (player_move == 3 and computer_move == 2):
        player_score += 10
        print(f"You win! Score: {player_score}")
    elif player_move == computer_move:
        print(f"Draw. Score: {player_score}")
    else:
        player_score -= 10
        print(f"You lose. Score: {player_score}")
    
    if player_score >= 200:
        print("Congratulations! You won the match!")
        break
    elif player_score <= 0:
        print("Game over. You lost.")
        break

Problem 12: Happy Numbers

A happy number eventually reaches 1 when replaced by the sum of the squares of its digits. If it loops endlessly without reaching 1, it's unhappy.

def digit_square_sum(n):
    total = 0
    for digit in str(n):
        total += int(digit) ** 2
    return total

current = int(input("Enter a number: "))
seen = []

while digit_square_sum(current) not in seen:
    current = digit_square_sum(current)
    seen.append(current)

if current == 1:
    print("Happy number!")
else:
    print("Not a happy number.")

Problem 13: Age Puzzle (Part 1)

Two sisters say: "The product of our ages is 6 times the sum of our ages." They are not twins (different ages) and their age difference is less than 8 years. Find the younger sister's age.

for age1 in range(1, 100):
    for age2 in range(1, age1):
        if age1 * age2 == 6 * (age1 + age2) and age1 - age2 < 8:
            print(f"Ages: {age1} and {age2}")
            print(f"Younger sister is {age2}")

Problem 14: Age Puzzle (Part 2)

Norbert Wiener's puzzle: "My age cubed is a 4-digit number. My age to the fourth power is a 6-digit number. Together, these 10 digits contain each digit 0-9 exactly once."

for age in range(10, 30):
    cube = str(age ** 3)
    fourth = str(age ** 4)
    
    if len(cube) == 4 and len(fourth) == 6:
        combined = cube + fourth
        if len(set(combined)) == 10:
            print(f"Age: {age}")
            print(f"Combined digits: {combined}")

Problem 15: Custom Split Implementation

Implement Python's split() method functionality manually. Track indices and slice the string when delimiters are encountered.

def custom_split(text, delimiter="", max_splits=0):
    result = []
    start_idx = 0
    split_count = 0
    
    for idx, char in enumerate(text):
        if max_splits > 0 and split_count == max_splits:
            result.append(text[start_idx:])
            break
        
        if char == delimiter:
            result.append(text[start_idx:idx])
            start_idx = idx + 1
            split_count += 1
        elif idx == len(text) - 1:
            result.append(text[start_idx:idx + 1])
    
    return result

# Test
print(custom_split("life-is-short-you-need-python", "-"))
# ['life', 'is', 'short', 'you', 'need', 'python']

print(custom_split("life-is-short-you-need-python", "-", 2))
# ['life', 'is', 'short-you-need-python']

Problem 16: Dayan Sequence

An ancient Chinese sequence: 0, 2, 4, 8, 12, 18, 24, 32, 40, 50...

  • For even indices $n$: $n^2 / 2$
  • For odd indices $n$: $(n^2 - 1) / 2$
for n in range(1, 101):
    if n % 2 == 0:
        value = (n ** 2) // 2
    else:
        value = (n ** 2 - 1) // 2
    print(value)

Problem 17: Character Frequency Analysis

Given a word, find the character that appears most frequently and its count.

def analyze_frequency(text):
    frequency = {}
    for char in text:
        frequency[char] = frequency.get(char, 0) + 1
    
    most_common = max(frequency, key=frequency.get)
    print(most_common)
    print(frequency[most_common])

analyze_frequency("HelloWorld")
# Output: 'l' and 3

Problem 18: Diamond Pattern Using Stack

Print a diamond pattern of given size using a stack to reverse the pattern for the lower half.

def print_diamond(size):
    lines = []
    for row in range(1, 2 * size):
        if row <= size:
            spaces = ' ' * (size - row)
            stars = '*' * (2 * row - 1)
            line = spaces + stars
            if row != size:
                lines.append(line)
            print(line)
        else:
            print(lines.pop())

print_diamond(5)

Problem 19: Understanding Recursion

Recursion occurs when a function calls itself. Each call creates a new stack frame. The function must have a base case to prevent infinite recursion.

def demonstrate_recursion(level):
    if level == 0:
        return
    print(f"Pre-recursion: {level}")
    demonstrate_recursion(level - 1)
    print(f"Post-recursion: {level}")

demonstrate_recursion(5)

Problem 20: Fibonacci with Recursion

The Fibonacci sequence: 1, 1, 2, 3, 5, 8, 13... where each number is the sum of the two preceding ones.

def fibonacci(n):
    if n <= 2:
        return 1
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(10))  # 55

Note: Eacch recursive call pushes a frame onto the call stack. The stack unwinds when base cases are reached, following the Last-In-First-Out (LIFO) principle.

Problem 21: Maximum of Three Numbers

Find the maximum of three values using only conditional statements (no max() function or lists).

x, y, z = 10, 6, 18

if x > y:
    maximum = x
else:
    maximum = y

if z > maximum:
    maximum = z

print(maximum)  # 18

Problem 22: Perfect Numbers

A perfect number equals the sum of its proper divisors (excluding itself). For example: $6 = 1 + 2 + 3$.

def sum_of_factors(number):
    total = 0
    for divisor in range(1, number):
        if number % divisor == 0:
            total += divisor
    return total

for candidate in range(1, 1000):
    if candidate == sum_of_factors(candidate):
        print(candidate)
        # Output: 6, 28, 496

Problem 23: Factorial Sum

Calculate $1! + 2! + 3! + ... + 10!$ using recursion.

def factorial(n):
    if n < 2:
        return 1
    return n * factorial(n - 1)

total_sum = 0
for k in range(1, 11):
    total_sum += factorial(k)

print(total_sum)  # 4037913

Problem 24: Valid Parentheses

Determine if a string containing just (, ), {, }, [, and ] is valid. Valid strings have matching pairs in correct order.

Method 1: String Replacement

def is_valid_replace(s):
    if len(s) % 2 == 1:
        return False
    while '()' in s or '[]' in s or '{}' in s:
        s = s.replace('()', '').replace('[]', '').replace('{}', '')
    return s == ''

Method 2: Stack-Based

def is_valid_stack(s):
    if len(s) % 2 == 1:
        return False
    
    brackets = []
    mapping = {')': '(', '}': '{', ']': '['}
    
    for char in s:
        if char in mapping:
            if not brackets or brackets.pop() != mapping[char]:
                return False
        else:
            brackets.append(char)
    
    return not brackets

print(is_valid_stack("(){}[({[]})]"))  # True
print(is_valid_stack("(){}[({[)})]"))  # False

Problem 25: Palindrome Number

A palindrome reads the same forwards and backwards.

Method 1: String Conversion

def check_palindrome_str(num):
    if num < 0 or (num > 0 and num % 10 == 0):
        return False
    as_string = str(num)
    return as_string == as_string[::-1]

Method 2: Reverse Half

def check_palindrome_half(num):
    if num < 0 or (num % 10 == 0 and num != 0):
        return False
    
    reversed_half = 0
    while num > reversed_half:
        reversed_half = reversed_half * 10 + num % 10
        num //= 10
    
    return num == reversed_half or num == reversed_half // 10

print(check_palindrome_half(1221))   # True
print(check_palindrome_half(12321))  # True
print(check_palindrome_half(12345))  # False

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.