From 23bf92a1e92e6870d410f3b9ab25b8ca99bf3d89 Mon Sep 17 00:00:00 2001
From: 3wish <hety13@chinaunicom.cn>
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