递归和动态规划
parent
b34bc34143
commit
23bf92a1e9
|
@ -1,2 +1,4 @@
|
||||||
.venv
|
.venv
|
||||||
|
.idea
|
||||||
test/.pytest_cache/
|
test/.pytest_cache/
|
||||||
|
**/__pycache__
|
|
@ -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]
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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]
|
|
@ -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)
|
|
@ -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)
|
Loading…
Reference in New Issue