递归和动态规划

main
3wish 2023-12-04 12:48:44 +08:00
parent b34bc34143
commit 23bf92a1e9
8 changed files with 226 additions and 1 deletions

4
.gitignore vendored
View File

@ -1,2 +1,4 @@
.venv
test/.pytest_cache/
.idea
test/.pytest_cache/
**/__pycache__

View File

@ -0,0 +1,52 @@
"""
动态规划的核心
将大问题分解为多个小问题通过解决一个个小问题
并保存解决每个小问题时的状态最终解决大问题
动态规划实现找零
1. 先看找零1元需要多少1
2. 找零2元需要多少两张1元
3. 找零3元需要多少找零2元的结果+找零1元的结果
"""
# 动态规划找零
def dp_rec_mc1(changes: list[int], cash: int):
min_changes = [0 for _ in range(cash + 1)]
for i in range(1, cash + 1):
min_amount = i
for c in filter(lambda x: x <= i, changes):
temp_min_amount = 1 + min_changes[i - c]
if temp_min_amount < min_amount:
min_amount = temp_min_amount
min_changes[i] = min_amount
return min_changes[cash]
# 动态规划找零,并保存每一种找零所需的纸币情况
def dp_rec_mc2(changes: list[int], cash: int):
change_used: dict[int, dict[int, int]] = {}
min_amounts = [0 for _ in range(cash + 1)]
for i in range(1, cash + 1):
min_amount = i
changes_less_then_i = filter(lambda x: x <= i, changes)
for c in changes_less_then_i:
temp_min_amount = 1 + min_amounts[i - c]
if temp_min_amount < min_amount:
min_amount = temp_min_amount
if i - c > 0:
change_used[i] = change_used[i - c].copy()
if change_used[i].get(c):
change_used[i][c] += 1
else:
change_used[i][c] = 1
else:
change_used[i] = {c: 1}
min_amounts[i] = min_amount
if min_amount == i:
change_used[i] = {1: i}
return change_used[cash]

View File

@ -0,0 +1,27 @@
class Node:
def __init__(self, value: int, children=None):
self.value = value
self.children = children
nodes1 = Node(1, [Node(2, [Node(4), Node(5)]), Node(3, [Node(6), Node(7)])])
nodes2 = Node(1, [Node(2, [Node(4), Node(5), Node(10, [Node(19), Node(39), Node(27)])]), Node(3, [Node(6), Node(7)])])
def iter_tree(node: Node):
res = [node.value]
def recursive(nodes: list[Node], temp_res: list[int]):
temp = []
for _node in nodes:
temp_res.append(_node.value)
if _node.children:
temp.extend(_node.children)
if len(temp) > 0:
recursive(temp, temp_res)
if node.children:
recursive(node.children, res)
return res

View File

@ -0,0 +1,49 @@
from typing import Self
class SinglyNode:
def __init__(self, value, nex: Self | None):
self.value = value
self.next = nex
def __repr__(self):
return f'Node({self.value})'
class SinglyLinkList:
__string = ''
def __init__(self):
self.size = 0
self.head: SinglyNode | None = None
def __repr__(self):
return self.__string
def is_empty(self) -> bool:
return self.size == 0
# 新节点总是添加到头部
def push(self, value):
if self.head is None:
self.__string = f'{value} -> None'
else:
self.__string = f'{value} -> ' + self.__string
node = SinglyNode(value, self.head)
self.head = node
self.size += 1
def pop(self) -> SinglyNode:
head = self.head
node = self.head.next
self.head = node
return head
def peek(self):
return self.head.value
def iter(self):
cur = self.head
while cur:
yield cur.value
cur = cur.next

View File

@ -0,0 +1,61 @@
"""
递归三定律
1
2
3
"""
def recursive_sum(nums: list):
if 1 == len(nums):
return nums[0]
return nums[0] + recursive_sum(nums[1:])
# 使用递归的方式实现进制转换
def recursive_num_conversion(num: int) -> str:
if num == 0:
return ''
return recursive_num_conversion(num // 2) + str(num % 2)
# 找零问题:类似贪婪,经量找出最少纸币搭配
def rec_mc1(changes: list[int], cash: int):
# 全用1元纸币时最少找零数
min_amount = cash
try:
if changes.index(cash):
return 1
except Exception as e:
for c in changes:
# cash - c表示使用了一张面额为c的来找零所以需要+1
num = 1 + rec_mc1(changes, cash-c)
if num < min_amount:
min_amount = num
return min_amount
def rec_mc2(changes: list[int], cash: int, min_changes: int,):
min_amount = cash
try:
if changes.index(cash):
min_changes[cash] = 1
return 1
except Exception as e:
if min_changes[cash] > 0:
return min_changes[cash]
else:
for c in changes:
num = 1 + rec_mc2(changes, cash - c, min_changes)
if num < min_amount:
min_amount = num
min_changes[cash] = min_amount
return min_amount

View File

@ -0,0 +1,12 @@
from dynamic_programming.dynamic_programming import *
def test_dp_rec_mc1():
cash = 49
changes = [1, 5, 10, 20, 50]
assert 7 == dp_rec_mc1(changes, cash)
def test_dp_rec_mc2():
cash = 49
changes = [1, 5, 10, 20, 50]

View File

@ -0,0 +1,12 @@
from link_list.singly_link import SinglyLinkList
def test_singly_link():
link_list = SinglyLinkList()
link_list.push(1)
link_list.push(2)
link_list.push(3)
link_list.push(4)
assert 4 == link_list.peek()
assert 4 == link_list.size
assert "4 -> 3 -> 2 -> 1 -> None" == repr(link_list)

View File

@ -0,0 +1,10 @@
from recursive.recursive import *
def test_recursive_sum():
nums = [1, 2, 3]
assert 6 == recursive_sum(nums)
def test_recursive_num_conversion():
num = 10
assert '1010' == recursive_num_conversion(num)