Python Arena
Step 3 of 4

Fibonacci, strings and lists

In the Fibonacci sequence, each number is the sum of the two numbers before it: 1, 1, 2, 3, 5, 8, 13 and so on. The definition has two base cases, the first two numbers, and its recursive case calls the function twice:

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


print([fibonacci(n) for n in range(1, 11)])
Output
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

You can check it one number at a time: fibonacci(3) is fibonacci(2) + fibonacci(1), which is 1 + 1 = 2. Then fibonacci(4) is fibonacci(3) + fibonacci(2), which is 2 + 1 = 3, and so on.

Two calls in every call add up fast, though. fibonacci(30) makes more than a million calls, because it works out the same smaller numbers again and again. A loop that remembers the two latest numbers is much faster. Recursion is often the clearest way to write something down, not always the fastest way to run it.

Smaller strings and lists

Recursion works whenever a problem has a smaller problem of the same kind inside it. A string without its first character is a shorter string, and a list without its first item is a shorter list. Slices give you those smaller pieces: text[1:] and numbers[1:]. The base case is often the empty string or the empty list.

The sum of a list is its first number plus the sum of the rest:

def list_sum(numbers):
    if len(numbers) == 0:
        return 0
    return numbers[0] + list_sum(numbers[1:])


print(list_sum([4, 8, 15, 16]))
Output
43

A string reversed is the rest of it reversed, with the first character at the end:

def reverse(text):
    if text == "":
        return ""
    return reverse(text[1:]) + text[0]


print(reverse("stressed"))
Output
desserts

A palindrome reads the same backwards, like "racecar". A string is a palindrome if its first and last characters are the same and the part between them, text[1:-1], is a palindrome too. A string of 0 or 1 characters is always one:

def is_palindrome(text):
    if len(text) <= 1:
        return True
    if text[0] != text[-1]:
        return False
    return is_palindrome(text[1:-1])


print(is_palindrome("racecar"))
print(is_palindrome("rocket"))
Output
True
False

This one has two base cases: a short string gives True, and a mismatch gives False straight away, without looking at the rest.

When you write a recursive function, ask yourself two questions. What is the simplest case, and what's its answer? And how does the answer for a slightly smaller problem help with the whole one?

Your task

Challenge 1 of 3

The function counts how many times a character appears in a text. Fill in the blank so the recursive call gets the rest of the text. The program should print:

3
0

Challenge 2

Write a recursive function largest(numbers) that returns the greatest number in a list that has at least one number. Don't use max or a loop: the greatest number is either the first one or the greatest of the rest.

For example, this call:

print(largest([3, 9, 4]))

prints:

9

Challenge 3

You climb a staircase taking either one or two steps at a time. A staircase of 3 steps can be climbed in 3 different ways: 1 + 1 + 1, 1 + 2 and 2 + 1. Write a recursive function ways(steps) that returns the number of different ways to climb a staircase of steps steps (at least 1).

Your first move is either one step or two. After one step, steps - 1 steps are left, and after two, steps - 2. So the number of ways is the ways for steps - 1 plus the ways for steps - 2. A staircase of 1 step can be climbed in 1 way, and one of 2 steps in 2 ways.

For example, this call:

print(ways(3))

prints:

3