From 23bf92a1e92e6870d410f3b9ab25b8ca99bf3d89 Mon Sep 17 00:00:00 2001 From: 3wish Date: Mon, 4 Dec 2023 12:48:44 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=92=E5=BD=92=E5=92=8C=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E8=A7=84=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- dynamic_programming/dynamic_programming.py | 52 ++++++++++++++++++ interview/iter_tree.py | 27 ++++++++++ link_list/singly_link.py | 49 +++++++++++++++++ recursive/recursive.py | 61 ++++++++++++++++++++++ test/test_dynamic_programming.py | 12 +++++ test/test_link_list.py | 12 +++++ test/test_recursive.py | 10 ++++ 8 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 dynamic_programming/dynamic_programming.py create mode 100644 interview/iter_tree.py create mode 100644 link_list/singly_link.py create mode 100644 recursive/recursive.py create mode 100644 test/test_dynamic_programming.py create mode 100644 test/test_link_list.py create mode 100644 test/test_recursive.py diff --git a/.gitignore b/.gitignore index cdd4b45..bf0191b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .venv -test/.pytest_cache/ \ No newline at end of file +.idea +test/.pytest_cache/ +**/__pycache__ \ No newline at end of file diff --git a/dynamic_programming/dynamic_programming.py b/dynamic_programming/dynamic_programming.py new file mode 100644 index 0000000..796557f --- /dev/null +++ b/dynamic_programming/dynamic_programming.py @@ -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] + diff --git a/interview/iter_tree.py b/interview/iter_tree.py new file mode 100644 index 0000000..9c73db3 --- /dev/null +++ b/interview/iter_tree.py @@ -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 diff --git a/link_list/singly_link.py b/link_list/singly_link.py new file mode 100644 index 0000000..1a8688d --- /dev/null +++ b/link_list/singly_link.py @@ -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 diff --git a/recursive/recursive.py b/recursive/recursive.py new file mode 100644 index 0000000..d544a18 --- /dev/null +++ b/recursive/recursive.py @@ -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 + diff --git a/test/test_dynamic_programming.py b/test/test_dynamic_programming.py new file mode 100644 index 0000000..70bed37 --- /dev/null +++ b/test/test_dynamic_programming.py @@ -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] \ No newline at end of file diff --git a/test/test_link_list.py b/test/test_link_list.py new file mode 100644 index 0000000..adde84d --- /dev/null +++ b/test/test_link_list.py @@ -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) \ No newline at end of file diff --git a/test/test_recursive.py b/test/test_recursive.py new file mode 100644 index 0000000..201f431 --- /dev/null +++ b/test/test_recursive.py @@ -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) \ No newline at end of file