log in
register

[Algorithm] Get into recursion in Python

Qingqi@2020-11-29 #algorithm and data structure

# references:
#   https://runestone.academy/runestone/books/published/pythonds/index.html
from copy import deepcopy


# sum numbers with recursion
def sum_recursion(nums):
    if nums:
        if len(nums) == 1:
            return nums[0]
        else:
            return nums[0] + sum_recursion(nums[1:])
    else:
        return 0


# The Three Laws of Recursion
# must have a base case
# must change its state and move toward the base case
# must call itself, recursively


# convert decimal to binary, hexadecimal or other base (<=16) number
def convert(decimal, base):
    extend_num_string = "0123456789ABCDEF"
    if decimal < base:
        return extend_num_string[decimal]
    return convert(decimal//base, base) + extend_num_string[decimal % base]


# use stack to implement recursion
def convert_stack(decimal, base):
    decimal = deepcopy(decimal)
    extend_num_string = "0123456789ABCDEF"
    stack = []
    output = ''
    while decimal > 0:
        stack.append(extend_num_string[decimal % base])
        decimal = decimal // 2
    while stack:
        output += stack.pop()
    return output


# Tower of Hanoi
# a helpful pic for this algorithm:
# https://en.wikipedia.org/wiki/Tower_of_Hanoi#/media/File:Tower_of_Hanoi_recursion_SMIL.svg
# the most important thing:
#   no need to follow or clear the whole process
#   only need to know what the function do
#   and make sure a problem could be solves by solving smaller problem
#   and how to solve the minimum problem
def move(i, start, end, mid):
    if i >= 1:
        move(i-1, start, mid, end)
        print('move {} from {} to {}'.format(i, start, end))
        move(i-1, mid, end, start)


move(5, 'A', 'C', 'B')


# making change using the fewest coins
# 1. inefficient way, compare with any possible cases, just like brute force
def make_change1(coin_list, change):
    min_coins = change
    if change in coin_list:
        return 1
    else:
        for i in coin_list:
            if i < change:
                num_coins = make_change1(coin_list, change-i) + 1
                if num_coins < min_coins:
                    min_coins = num_coins
    return min_coins


# 2. with caching technique, remember the known information
def make_change2(coin_list, change, known_dict={}):
    min_coins = change
    if change in known_dict:
        return known_dict[change]
    elif change in coin_list:
        known_dict[change] = 1
        return 1
    else:
        for i in coin_list:
            if i < change:
                num_coins = make_change2(coin_list, change-i, known_dict) + 1
                if num_coins < min_coins:
                    min_coins = num_coins
        known_dict[change] = min_coins
    return min_coins


# 3. Dynamic programming
# extend min_coins_dict for each iteration
# could get a dict for result of change in range(1, input+1)
def make_change3(coin_list, change):
    min_coins_dict = {}
    # start from 0, because we need min_coins_dict[0] = 0
    for x in range(change+1):
        num_coins = x
        for i in coin_list:
            # NB! here use i <= x, not i<x as before
            if i <= x and min_coins_dict[x-i]+1 < num_coins:
                num_coins = min_coins_dict[x-i]+1
        min_coins_dict[x] = num_coins
    return min_coins_dict


make_change1([1, 5, 10, 20], 63)
make_change2([1, 5, 10, 20], 63)
make_change3([1, 5, 10, 20], 63)
Comments

Log in to add your comment

Don't have an account? register here