From a7d109c82a30746df01e15fc95ebda43e3ad9c81 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sat, 7 Dec 2024 19:42:19 +0800 Subject: [PATCH 01/17] Update 01.Array-Bubble-Sort.md --- .../02.Array-Sort/01.Array-Bubble-Sort.md | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/Contents/01.Array/02.Array-Sort/01.Array-Bubble-Sort.md b/Contents/01.Array/02.Array-Sort/01.Array-Bubble-Sort.md index e1dd3bc9..ea2ac53c 100644 --- a/Contents/01.Array/02.Array-Sort/01.Array-Bubble-Sort.md +++ b/Contents/01.Array/02.Array-Sort/01.Array-Bubble-Sort.md @@ -89,6 +89,49 @@ class Solution: return self.bubbleSort(nums) ``` + +```python + +class Solution: + def bubbleSort(self, nums: [int]) -> [int]: + # 第 i 趟「冒泡」 + for i in range(len(nums) - 1): + flag = False # 是否发生交换的标志位 + # 从数组中前 n - i + 1 个元素的第 1 个元素开始,相邻两个元素进行比较 + for j in range(len(nums) - i - 1): + # 相邻两个元素进行比较,如果前者大于后者,则交换位置 + if nums[j] > nums[j + 1]: + nums[j], nums[j + 1] = nums[j + 1], nums[j] + flag = True + if not flag: # 此趟遍历未交换任何元素,直接跳出 + break + + return nums + + def sortArray(self, nums: [int]) -> [int]: + return self.bubbleSort(nums) + + + +# 创建 Solution 类的实例 +solution = Solution() + +# 定义一个整数列表 +nums = [5, 3, 8, 6, 2] + +# 调用 sortArray 方法对列表进行排序 +sorted_nums = solution.sortArray(nums) + + +# 输出排序后的结果 +print(sorted_nums) # 输出: [2, 3, 5, 6, 8] + + +``` + + + + ## 4. 冒泡排序算法分析 - **最佳时间复杂度**:$O(n)$。最好的情况下(初始时序列已经是升序排列),只需经过 $1$ 趟排序,总共经过 $n$ 次元素之间的比较,并且不移动元素,算法就可以结束排序。因此,冒泡排序算法的最佳时间复杂度为 $O(n)$。 @@ -99,4 +142,4 @@ class Solution: ## 参考资料 -- 【文章】[11.3. 冒泡排序 - Hello 算法](https://www.hello-algo.com/chapter_sorting/bubble_sort/) \ No newline at end of file +- 【文章】[11.3. 冒泡排序 - Hello 算法](https://www.hello-algo.com/chapter_sorting/bubble_sort/) From 1e32dbc83bcfc2f4072b7d74e9eac96518bf60c1 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sat, 7 Dec 2024 19:48:53 +0800 Subject: [PATCH 02/17] Update 01.Array-Bubble-Sort.md --- Contents/01.Array/02.Array-Sort/01.Array-Bubble-Sort.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Contents/01.Array/02.Array-Sort/01.Array-Bubble-Sort.md b/Contents/01.Array/02.Array-Sort/01.Array-Bubble-Sort.md index ea2ac53c..d30012a9 100644 --- a/Contents/01.Array/02.Array-Sort/01.Array-Bubble-Sort.md +++ b/Contents/01.Array/02.Array-Sort/01.Array-Bubble-Sort.md @@ -2,7 +2,8 @@ > **冒泡排序(Bubble Sort)基本思想**: > -> 经过多次迭代,通过相邻元素之间的比较与交换,使值较小的元素逐步从后面移到前面,值较大的元素从前面移到后面。 +> 1,确定最大的放在最后面, +> 2,经过多次迭代,通过相邻元素之间的比较与交换,使值较小的元素逐步从后面移到前面,值较大的元素从前面移到后面。 这个过程就像水底的气泡一样从底部向上「冒泡」到水面,这也是冒泡排序法名字的由来。 From 7ee7f2f90205c34bd96dc43371ad4ef6836fd1e4 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sat, 7 Dec 2024 22:38:49 +0800 Subject: [PATCH 03/17] =?UTF-8?q?Update=200002.=20=E4=B8=A4=E6=95=B0?= =?UTF-8?q?=E7=9B=B8=E5=8A=A0.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...44\346\225\260\347\233\270\345\212\240.md" | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git "a/Solutions/0002. \344\270\244\346\225\260\347\233\270\345\212\240.md" "b/Solutions/0002. \344\270\244\346\225\260\347\233\270\345\212\240.md" index 81ba2e09..c2d8359c 100644 --- "a/Solutions/0002. \344\270\244\346\225\260\347\233\270\345\212\240.md" +++ "b/Solutions/0002. \344\270\244\346\225\260\347\233\270\345\212\240.md" @@ -72,7 +72,70 @@ class Solution: return head.next ``` + + + +```python +class ListNode: + def __init__(self, val=0, next=None): + self.val = val + self.next = next + +class Solution: + def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: + head = curr = ListNode(0) # 创建虚假头节点 + carry = 0 # 进位 + + # 遍历两个链表直到都遍历完并且没有进位 + while l1 or l2 or carry: + num1 = l1.val if l1 else 0 # 获取当前位的值 + num2 = l2.val if l2 else 0 # 获取当前位的值 + + # 计算当前位的和 + sum = num1 + num2 + carry + carry = sum // 10 # 更新进位 + curr.next = ListNode(sum % 10) # 创建新节点并链接 + + # 移动指针 + curr = curr.next + if l1: l1 = l1.next + if l2: l2 = l2.next + + return head.next # 返回去除虚假头节点的链表 + +# 辅助函数:将列表转换为链表 +def list_to_linkedlist(lst): + dummy = ListNode() # 创建虚假头节点 + curr = dummy + for val in lst: + curr.next = ListNode(val) + curr = curr.next + return dummy.next + +# 将链表转换为列表 +def linkedlist_to_list(node): + result = [] + while node: + result.append(node.val) + node = node.next + return result + +# 示例 +l1 = list_to_linkedlist([2, 4, 3]) # 342 +l2 = list_to_linkedlist([5, 6, 4]) # 465 + +solution = Solution() +result = solution.addTwoNumbers(l1, l2) + +print(linkedlist_to_list(result)) # 输出 [7, 0, 8],表示数字 807 +``` + + + + + + ### 思路 1:复杂度分析 - **时间复杂度**:$O(max(m, n))$。其中,$m$ 和 $n$ 分别是链表 `l1` 和 `l2` 的长度。 -- **空间复杂度**:$O(1)$。 \ No newline at end of file +- **空间复杂度**:$O(1)$。 From 0b753f8c8bed7b7e24f3e7aa380113b0d9434a64 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sat, 7 Dec 2024 22:45:03 +0800 Subject: [PATCH 04/17] =?UTF-8?q?Update=200003.=20=E6=97=A0=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=AD=97=E7=AC=A6=E7=9A=84=E6=9C=80=E9=95=BF=E5=AD=90?= =?UTF-8?q?=E4=B8=B2.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\232\204\346\234\200\351\225\277\345\255\220\344\270\262.md" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/Solutions/0003. \346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.md" "b/Solutions/0003. \346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.md" index 888ebc90..2d14906c 100644 --- "a/Solutions/0003. \346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.md" +++ "b/Solutions/0003. \346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.md" @@ -48,6 +48,8 @@ 4. 如果该窗口中该字符的个数多于 $1$ 个,即 $window[s[right]] > 1$,则不断右移 $left$,缩小滑动窗口长度,并更新窗口中对应字符的个数,直到 $window[s[right]] \le 1$。 5. 维护更新无重复字符的最长子串长度。然后继续右移 $right$,直到 $right \ge len(nums)$ 结束。 6. 输出无重复字符的最长子串长度。 +7. NOTE:字符串本质是特殊的list +8. NOTE:引入一个window来专门统计数据 ### 思路 1:代码 From 45054526667e39354786ed7d7a35fbe10e9ca2a7 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sat, 7 Dec 2024 22:45:59 +0800 Subject: [PATCH 05/17] =?UTF-8?q?Update=200003.=20=E6=97=A0=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=AD=97=E7=AC=A6=E7=9A=84=E6=9C=80=E9=95=BF=E5=AD=90?= =?UTF-8?q?=E4=B8=B2.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...00\351\225\277\345\255\220\344\270\262.md" | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git "a/Solutions/0003. \346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.md" "b/Solutions/0003. \346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.md" index 2d14906c..95ea4dfc 100644 --- "a/Solutions/0003. \346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.md" +++ "b/Solutions/0003. \346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.md" @@ -77,6 +77,45 @@ class Solution: return ans ``` + +```python +class Solution: + def lengthOfLongestSubstring(self, s: str) -> int: + # 左指针和右指针初始化 + left = 0 + right = 0 + # 使用字典存储窗口内每个字符的出现次数 + window = dict() + # 记录最长无重复子串的长度 + ans = 0 + + # 右指针不断向右扩展窗口 + while right < len(s): + # 将当前字符添加到窗口中 + window[s[right]] = window.get(s[right], 0) + 1 + + # 如果当前字符出现超过1次,说明有重复字符,需要收缩左边界 + while window[s[right]] > 1: + window[s[left]] -= 1 # 左指针指向的字符移出窗口 + left += 1 # 移动左指针 + + # 更新答案:当前窗口的大小是 (right - left + 1) + ans = max(ans, right - left + 1) + + # 移动右指针,扩展窗口 + right += 1 + + return ans # 返回最大长度 + +# 测试示例 +s = "abcabcbb" +solution = Solution() +result = solution.lengthOfLongestSubstring(s) +print(result) # 输出:3 + +``` + + ### 思路 1:复杂度分析 - **时间复杂度**:$O(n)$。 From 31346f8006b181bee310b93f5ed7b80091787d5d Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sat, 7 Dec 2024 23:19:30 +0800 Subject: [PATCH 06/17] =?UTF-8?q?Update=20=E5=89=91=E6=8C=87=20Offer=2009.?= =?UTF-8?q?=20=E7=94=A8=E4=B8=A4=E4=B8=AA=E6=A0=88=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E9=98=9F=E5=88=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...36\347\216\260\351\230\237\345\210\227.md" | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git "a/Solutions/\345\211\221\346\214\207 Offer 09. \347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.md" "b/Solutions/\345\211\221\346\214\207 Offer 09. \347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.md" index ba129782..8af2a3bb 100644 --- "a/Solutions/\345\211\221\346\214\207 Offer 09. \347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.md" +++ "b/Solutions/\345\211\221\346\214\207 Offer 09. \347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.md" @@ -49,3 +49,48 @@ class CQueue: return top ``` + +一个更为优雅的版本为:直接用了deque和book.popleft +```python +class CQueue: + + def __init__(self): + self.book = deque() + + def appendTail(self, value: int) -> None: + book = self.book + book.append(value) + + + def deleteHead(self) -> int: + book = self.book + if len(book) == 0: + return -1 + return book.popleft() + +``` +或者 +```python +class CQueue: + + def __init__(self): + self.stack1 = [] + self.stack2 = [] + + def appendTail(self, value: int) -> None: + self.stack1.append(value) + + def deleteHead(self) -> int: + if self.stack2 == []: + if self.stack1 == []: + return -1 + while self.stack1: + self.stack2.append(self.stack1.pop()) + return self.stack2.pop() + + +# Your CQueue object will be instantiated and called as such: +# obj = CQueue() +# obj.appendTail(value) +# param_2 = obj.deleteHead() +``` From 5da7f49ebef108abff36ae037479cba3fbd66f80 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sun, 8 Dec 2024 15:24:46 +0800 Subject: [PATCH 07/17] =?UTF-8?q?Update=20=E5=89=91=E6=8C=87=20Offer=20II?= =?UTF-8?q?=20119.=20=E6=9C=80=E9=95=BF=E8=BF=9E=E7=BB=AD=E5=BA=8F?= =?UTF-8?q?=E5=88=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...36\347\273\255\345\272\217\345\210\227.md" | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git "a/Solutions/\345\211\221\346\214\207 Offer II 119. \346\234\200\351\225\277\350\277\236\347\273\255\345\272\217\345\210\227.md" "b/Solutions/\345\211\221\346\214\207 Offer II 119. \346\234\200\351\225\277\350\277\236\347\273\255\345\272\217\345\210\227.md" index c3f073c2..94d6a27b 100644 --- "a/Solutions/\345\211\221\346\214\207 Offer II 119. \346\234\200\351\225\277\350\277\236\347\273\255\345\272\217\345\210\227.md" +++ "b/Solutions/\345\211\221\346\214\207 Offer II 119. \346\234\200\351\225\277\350\277\236\347\273\255\345\272\217\345\210\227.md" @@ -29,18 +29,35 @@ ```python class Solution: def longestConsecutive(self, nums: List[int]) -> int: - ans = 0 - nums_set = set(nums) - for num in nums_set: - if num - 1 not in nums_set: - curr_num = num - curr_streak = 1 - - while curr_num + 1 in nums_set: - curr_num += 1 - curr_streak += 1 - ans = max(ans, curr_streak) - - return ans + longest_streak = 0 + num_set = set(nums) # 这里使用set这种专门的操作 + + # 记录最长连续序列的长度 + for num in num_set: + if num - 1 not in num_set: + # 如果当前数字是序列的起始点(num-1 不在集合中),就开始找连续序列 + current_num = num + current_streak = 1 + + + # 继续向后找连续的数字 + while current_num + 1 in num_set: + current_num += 1 + current_streak += 1 + + # 更新最长连续序列的长度 + longest_streak = max(longest_streak, current_streak) + + return longest_streak + + +""" +这个题的主要idea在于 +1,利用了set的特性:唯一性,查找速度快 + -使用了in来快速基于哈希进行查找 + -上来就把list转化成set +2,用直接查找值的-1来作为起点 +3,利用了max +""" ``` From a2af8c299c42b725abd9875921704ac79d1982aa Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sun, 8 Dec 2024 15:55:41 +0800 Subject: [PATCH 08/17] =?UTF-8?q?Update=20=E5=89=91=E6=8C=87=20Offer=20II?= =?UTF-8?q?=20118.=20=E5=A4=9A=E4=BD=99=E7=9A=84=E8=BE=B9.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...32\344\275\231\347\232\204\350\276\271.md" | 59 +++++++++++-------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git "a/Solutions/\345\211\221\346\214\207 Offer II 118. \345\244\232\344\275\231\347\232\204\350\276\271.md" "b/Solutions/\345\211\221\346\214\207 Offer II 118. \345\244\232\344\275\231\347\232\204\350\276\271.md" index bab8778f..79c34374 100644 --- "a/Solutions/\345\211\221\346\214\207 Offer II 118. \345\244\232\344\275\231\347\232\204\350\276\271.md" +++ "b/Solutions/\345\211\221\346\214\207 Offer II 118. \345\244\232\344\275\231\347\232\204\350\276\271.md" @@ -24,35 +24,48 @@ ## 代码 ```python -class UnionFind: +class Solution: + def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: - def __init__(self, n): - self.parent = [i for i in range(n)] - def find(self, x): - while x != self.parent[x]: - self.parent[x] = self.parent[self.parent[x]] - x = self.parent[x] - return x + + n = len(edges) # n 是边的数量,实际上也是节点数量的上限 - def union(self, x, y): - root_x = self.find(x) - root_y = self.find(y) - self.parent[root_x] = root_y - def is_connected(self, x, y): - return self.find(x) == self.find(y) + # 初始化并查集,parent[i] 表示节点 i 的父节点,初始时每个节点的父节点都是自己 + # 这里就是直接基于n生成一个列表 + parent = list(range(n + 1)) # 从 1 到 n 的节点,所以大小为 n+1 -class Solution: - def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: - size = len(edges) - union_find = UnionFind(size + 1) - for edge in edges: - if union_find.is_connected(edge[0], edge[1]): - return edge - union_find.union(edge[0], edge[1]) + # 查找操作,找到节点所在集合的根节点 + def find(index: int) -> int: + if parent[index] != index: + # 路径压缩,递归查找父节点并将其直接指向根节点 + parent[index] = find(parent[index]) + return parent[index] + + # 合并操作,将两个节点所在集合合并 + def union(index1: int, index2: int): + parent[find(index1)] = find(index2) + + # 遍历所有的边 + for node1, node2 in edges: + # 如果 node1 和 node2 已经在同一个连通分量中,则添加的边形成了环,返回这条边 + if find(node1) != find(node2): + # 如果不在同一个集合,进行合并 + union(node1, node2) + else: + # 如果已经在同一集合,说明形成了环,返回当前这条边 + return [node1, node2] + + return [] + +""" +这个图本质是找环 + +1,先生成一个直接的节点 + - return None +""" ``` From cc32ace31b53c69fc19beb35fd4505dc67611b09 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sun, 8 Dec 2024 16:09:04 +0800 Subject: [PATCH 09/17] =?UTF-8?q?Update=20=E5=89=91=E6=8C=87=20Offer=20II?= =?UTF-8?q?=20116.=20=E7=9C=81=E4=BB=BD=E6=95=B0=E9=87=8F.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...01\344\273\275\346\225\260\351\207\217.md" | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git "a/Solutions/\345\211\221\346\214\207 Offer II 116. \347\234\201\344\273\275\346\225\260\351\207\217.md" "b/Solutions/\345\211\221\346\214\207 Offer II 116. \347\234\201\344\273\275\346\225\260\351\207\217.md" index 1ab9cace..03547924 100644 --- "a/Solutions/\345\211\221\346\214\207 Offer II 116. \347\234\201\344\273\275\346\225\260\351\207\217.md" +++ "b/Solutions/\345\211\221\346\214\207 Offer II 116. \347\234\201\344\273\275\346\225\260\351\207\217.md" @@ -62,3 +62,26 @@ class Solution: return union_find.count ``` +直接使用并集,大力出奇迹 +```python +class Solution: + def findCircleNum(self, isConnected: List[List[int]]) -> int: + def dfs(i: int): + for j in range(cities): + if isConnected[i][j] == 1 and j not in visited: + visited.add(j) + dfs(j) + + cities = len(isConnected) + visited = set() + provinces = 0 + + for i in range(cities): + if i not in visited: + dfs(i) + provinces += 1 + + return provinces + + +``` From 671648be0e445d779d758078ffd5ab2b3837ff91 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sun, 8 Dec 2024 16:44:45 +0800 Subject: [PATCH 10/17] =?UTF-8?q?Update=20=E5=89=91=E6=8C=87=20Offer=20II?= =?UTF-8?q?=20112.=20=E6=9C=80=E9=95=BF=E9=80=92=E5=A2=9E=E8=B7=AF?= =?UTF-8?q?=E5=BE=84.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...22\345\242\236\350\267\257\345\276\204.md" | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git "a/Solutions/\345\211\221\346\214\207 Offer II 112. \346\234\200\351\225\277\351\200\222\345\242\236\350\267\257\345\276\204.md" "b/Solutions/\345\211\221\346\214\207 Offer II 112. \346\234\200\351\225\277\351\200\222\345\242\236\350\267\257\345\276\204.md" index 35d4a239..39380255 100644 --- "a/Solutions/\345\211\221\346\214\207 Offer II 112. \346\234\200\351\225\277\351\200\222\345\242\236\350\267\257\345\276\204.md" +++ "b/Solutions/\345\211\221\346\214\207 Offer II 112. \346\234\200\351\225\277\351\200\222\345\242\236\350\267\257\345\276\204.md" @@ -21,29 +21,44 @@ ```python class Solution: - max_len = 0 - directions = {(1, 0), (-1, 0), (0, 1), (0, -1)} + + DIRS = [(-1, 0), (1, 0), (0, -1), (0, 1)] def longestIncreasingPath(self, matrix: List[List[int]]) -> int: + + + # 如果矩阵为空,返回 0 if not matrix: return 0 - rows, cols = len(matrix), len(matrix[0]) - record = [[0 for _ in range(cols)] for _ in range(rows)] - - def dfs(i, j): - record[i][j] = 1 - for direction in self.directions: - new_i, new_j = i + direction[0], j + direction[1] - if 0 <= new_i < rows and 0 <= new_j < cols and matrix[new_i][new_j] > matrix[i][j]: - if record[new_i][new_j] == 0: - dfs(new_i, new_j) - record[i][j] = max(record[i][j], record[new_i][new_j] + 1) - self.max_len = max(self.max_len, record[i][j]) + + # 定义一个递归函数来进行深度优先搜索(DFS),并使用 lru_cache 来缓存结果 + @lru_cache(None) # 使用缓存来优化递归,避免重复计算相同的子问题 + def dfs(row: int, column: int) -> int: + # 当前路径的最小长度为 1(当前节点本身) + best = 1 + # 遍历四个方向:上、下、左、右 + for dx, dy in Solution.DIRS: + # 计算新位置的行列坐标 + newRow, newColumn = row + dx, column + dy + # 检查新位置是否在矩阵范围内,并且新位置的值大于当前节点的值 + if 0 <= newRow < rows and 0 <= newColumn < columns and matrix[newRow][newColumn] > matrix[row][column]: + # 如果条件满足,递归地计算从新位置开始的最长递增路径,并更新 best + best = max(best, dfs(newRow, newColumn) + 1) + + # 返回当前节点的最长递增路径长度 + return best + # 初始化答案为 0 + ans = 0 + # 获取矩阵的行数和列数 + rows, columns = len(matrix), len(matrix[0]) + + # 遍历矩阵的每个节点,计算每个节点作为起点的最长递增路径 for i in range(rows): - for j in range(cols): - if record[i][j] == 0: - dfs(i, j) - return self.max_len + for j in range(columns): + # 更新答案,取当前节点的最长递增路径和已找到的最长路径的最大值 + ans = max(ans, dfs(i, j)) + return ans + ``` From 0ade9d58abd5d66c10395d25a8f077f03d15be2e Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sun, 8 Dec 2024 17:01:24 +0800 Subject: [PATCH 11/17] =?UTF-8?q?Update=20=E5=89=91=E6=8C=87=20Offer=20II?= =?UTF-8?q?=20111.=20=E8=AE=A1=E7=AE=97=E9=99=A4=E6=B3=95.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...41\347\256\227\351\231\244\346\263\225.md" | 158 +++++++++++------- 1 file changed, 99 insertions(+), 59 deletions(-) diff --git "a/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" "b/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" index 06c3db6d..3cadcc3f 100644 --- "a/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" +++ "b/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" @@ -47,69 +47,109 @@ ## 代码 ```python -class UnionFind: - - def __init__(self, n): - self.parent = [i for i in range(n)] - self.multiples = [1 for _ in range(n)] - - def find(self, x): - multiple = 1.0 - origin = x - while x != self.parent[x]: - multiple *= self.multiples[x] - x = self.parent[x] - self.parent[origin] = x - self.multiples[origin] = multiple - return x - - def union(self, x, y, multiple): - root_x = self.find(x) - root_y = self.find(y) - if root_x == root_y: - return - self.parent[root_x] = root_y - self.multiples[root_x] = multiple * self.multiples[y] / self.multiples[x] - return - - def is_connected(self, x, y): - root_x = self.find(x) - root_y = self.find(y) - if root_x != root_y: - return -1.0 +# [剑指 Offer II 111. 计算除法](https://leetcode.cn/problems/vlzXQL/) - return self.multiples[x] / self.multiples[y] +- 标签:深度优先搜索、广度优先搜索、并查集、图、数组、最短路 +- 难度:中等 +## 题目链接 + +- [剑指 Offer II 111. 计算除法 - 力扣](https://leetcode.cn/problems/vlzXQL/) + +## 题目大意 + +给定一个变量对数组 `equations` 和一个实数数组 `values` 作为已知条件,其中 `equations[i] = [Ai, Bi]` 和 `values[i]` 共同表示 `Ai / Bi = values[i]`。每个 `Ai` 或 `Bi` 是一个表示单个变量的字符串。 + +再给定一个表示多个问题的数组 `queries`,其中 `queries[j] = [Cj, Dj]` 表示第 `j` 个问题,要求:根据已知条件找出 `Cj / Dj = ?` 的结果作为答案。返回所有问题的答案。如果某个答案无法确定,则用 `-1.0` 代替,如果问题中出现了给定的已知条件中没有出现的表示变量的字符串,则也用 `-1.0` 代替这个答案。 + +## 解题思路 + +在「[等式方程的可满足性](https://leetcode.cn/problems/satisfiability-of-equality-equations)」的基础上增加了倍数关系。在「[等式方程的可满足性](https://leetcode.cn/problems/satisfiability-of-equality-equations)」中我们处理传递关系使用了并查集,这道题也是一样,不过在使用并查集的同时还要维护倍数关系。 + +举例说明: + +- `a / b = 2.0`:说明 `a = 2b`,`a` 和 `b` 在同一个集合。 +- `b / c = 3.0`:说明 `b = 3c`,`b` 和 `c` 在同一个集合。 + +根据上述两式可得:`a`、`b`、`c` 都在一个集合中,且 `a = 2b = 6c`。 + +我们可以将同一集合中的变量倍数关系都转换为与根节点变量的倍数关系,比如上述例子中都转变为与 `a` 的倍数关系。 + +具体操作如下: + +- 定义并查集结构,并在并查集中定义一个表示倍数关系的 `multiples` 数组。 +- 遍历 `equations` 数组、`values` 数组,将每个变量按顺序编号,并使用 `union` 将其并入相同集合。 +- 遍历 `queries` 数组,判断两个变量是否在并查集中,并且是否在同一集合。如果找到对应关系,则将计算后的倍数关系存入答案数组,否则则将 `-1` 存入答案数组。 +- 最终输出答案数组。 + +并查集中维护倍数相关方法说明: + +- `find` 方法: + - 递推寻找根节点,并将倍数累乘,然后进行路径压缩,并且更新当前节点的倍数关系。 +- `union` 方法: + - 如果两个节点属于同一集合,则直接返回。 + - 如果两个节点不属于同一个集合,合并之前当前节点的倍数关系更新,然后再进行更新。 +- `is_connect` 方法: + - 如果两个节点不属于同一集合,返回 `-1`。 + - 如果两个节点属于同一集合,则返回倍数关系。 + +## 代码 + +```python +from collections import defaultdict class Solution: - def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]: - equations_size = len(equations) - hash_map = dict() - union_find = UnionFind(2 * equations_size) - - id = 0 - for i in range(equations_size): - equation = equations[i] - var1, var2 = equation[0], equation[1] - if var1 not in hash_map: - hash_map[var1] = id - id += 1 - if var2 not in hash_map: - hash_map[var2] = id - id += 1 - union_find.union(hash_map[var1], hash_map[var2], values[i]) - - queries_size = len(queries) - res = [] - for i in range(queries_size): - query = queries[i] - var1, var2 = query[0], query[1] - if var1 not in hash_map or var2 not in hash_map: - res.append(-1.0) - else: - id1 = hash_map[var1] - id2 = hash_map[var2] - res.append(union_find.is_connected(id1, id2)) + def calcEquation(self, equations, values, queries): + # 构图:使用 defaultdict 来构建一个图,图的每个节点是一个变量,边的权重是该变量之间的比值 + graph = defaultdict(dict) + + # 遍历每个等式和对应的值,构建图 + for (a, b), value in zip(equations, values): + graph[a][b] = value + graph[b][a] = 1 / value + + # 定义深度优先搜索(DFS)函数来找路径 + def dfs(start,end,visited): + # 如果 start 或者 end 不在图中,说明无法找到路径,返回 -1.0 + if start not in graph or end not in graph: + return -1.0 + + + # 如果 start 和 end 相同,说明路径长度为 1.0,直接返回 + if start==end: + return 1.0 + + + # 标记当前节点为已访问,避免重复访问同一个节点 + visited.add(start) + + # 遍历从 start 出发的所有边(即 start 连接到其他节点的所有比值) + for i,value in graph[start].items(): + # 如果 i 还没有被访问过,继续递归查找路径 + if i not in visited: + # 递归查找从 i 到 end 的路径,并计算路径的比值 + path_value = dfs(i,end,visited) + + # 如果找到了有效路径,返回当前边的比值乘以路径的比值 + if path_value!=-1.0: + return value*path_value + + + # 如果没有找到路径,返回 -1.0 + return -1.0 + + # 用来存储查询结果的列表 + res=[] + + # 遍历所有的查询,使用 DFS 查找每一对查询的比值 + for start,end in queries: + # 对每个查询调用 DFS,查询 start 和 end 之间的比值 + res.append(dfs(start,end,set())) return res + + +""" + + ``` From df028f0faaee5bf99d14411ed9ef35f4262eee65 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sun, 8 Dec 2024 17:01:43 +0800 Subject: [PATCH 12/17] =?UTF-8?q?Update=20=E5=89=91=E6=8C=87=20Offer=20II?= =?UTF-8?q?=20111.=20=E8=AE=A1=E7=AE=97=E9=99=A4=E6=B3=95.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" "b/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" index 3cadcc3f..186f02e2 100644 --- "a/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" +++ "b/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" @@ -149,7 +149,7 @@ class Solution: """ - +""" ``` From 6898f136f2c5f6d3b7e916a8a18e2eb3513a1367 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sun, 8 Dec 2024 17:02:00 +0800 Subject: [PATCH 13/17] =?UTF-8?q?Update=20=E5=89=91=E6=8C=87=20Offer=20II?= =?UTF-8?q?=20111.=20=E8=AE=A1=E7=AE=97=E9=99=A4=E6=B3=95.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ... 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" | 4 ---- 1 file changed, 4 deletions(-) diff --git "a/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" "b/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" index 186f02e2..f99b0889 100644 --- "a/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" +++ "b/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" @@ -147,9 +147,5 @@ class Solution: res.append(dfs(start,end,set())) return res - -""" -""" - ``` From c04b6f4519cf9e51550e64bf1f4695d924f91a5d Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sun, 8 Dec 2024 17:02:31 +0800 Subject: [PATCH 14/17] =?UTF-8?q?Update=20=E5=89=91=E6=8C=87=20Offer=20II?= =?UTF-8?q?=20111.=20=E8=AE=A1=E7=AE=97=E9=99=A4=E6=B3=95.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...41\347\256\227\351\231\244\346\263\225.md" | 49 ------------------- 1 file changed, 49 deletions(-) diff --git "a/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" "b/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" index f99b0889..b9340973 100644 --- "a/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" +++ "b/Solutions/\345\211\221\346\214\207 Offer II 111. \350\256\241\347\256\227\351\231\244\346\263\225.md" @@ -46,55 +46,6 @@ ## 代码 -```python -# [剑指 Offer II 111. 计算除法](https://leetcode.cn/problems/vlzXQL/) - -- 标签:深度优先搜索、广度优先搜索、并查集、图、数组、最短路 -- 难度:中等 - -## 题目链接 - -- [剑指 Offer II 111. 计算除法 - 力扣](https://leetcode.cn/problems/vlzXQL/) - -## 题目大意 - -给定一个变量对数组 `equations` 和一个实数数组 `values` 作为已知条件,其中 `equations[i] = [Ai, Bi]` 和 `values[i]` 共同表示 `Ai / Bi = values[i]`。每个 `Ai` 或 `Bi` 是一个表示单个变量的字符串。 - -再给定一个表示多个问题的数组 `queries`,其中 `queries[j] = [Cj, Dj]` 表示第 `j` 个问题,要求:根据已知条件找出 `Cj / Dj = ?` 的结果作为答案。返回所有问题的答案。如果某个答案无法确定,则用 `-1.0` 代替,如果问题中出现了给定的已知条件中没有出现的表示变量的字符串,则也用 `-1.0` 代替这个答案。 - -## 解题思路 - -在「[等式方程的可满足性](https://leetcode.cn/problems/satisfiability-of-equality-equations)」的基础上增加了倍数关系。在「[等式方程的可满足性](https://leetcode.cn/problems/satisfiability-of-equality-equations)」中我们处理传递关系使用了并查集,这道题也是一样,不过在使用并查集的同时还要维护倍数关系。 - -举例说明: - -- `a / b = 2.0`:说明 `a = 2b`,`a` 和 `b` 在同一个集合。 -- `b / c = 3.0`:说明 `b = 3c`,`b` 和 `c` 在同一个集合。 - -根据上述两式可得:`a`、`b`、`c` 都在一个集合中,且 `a = 2b = 6c`。 - -我们可以将同一集合中的变量倍数关系都转换为与根节点变量的倍数关系,比如上述例子中都转变为与 `a` 的倍数关系。 - -具体操作如下: - -- 定义并查集结构,并在并查集中定义一个表示倍数关系的 `multiples` 数组。 -- 遍历 `equations` 数组、`values` 数组,将每个变量按顺序编号,并使用 `union` 将其并入相同集合。 -- 遍历 `queries` 数组,判断两个变量是否在并查集中,并且是否在同一集合。如果找到对应关系,则将计算后的倍数关系存入答案数组,否则则将 `-1` 存入答案数组。 -- 最终输出答案数组。 - -并查集中维护倍数相关方法说明: - -- `find` 方法: - - 递推寻找根节点,并将倍数累乘,然后进行路径压缩,并且更新当前节点的倍数关系。 -- `union` 方法: - - 如果两个节点属于同一集合,则直接返回。 - - 如果两个节点不属于同一个集合,合并之前当前节点的倍数关系更新,然后再进行更新。 -- `is_connect` 方法: - - 如果两个节点不属于同一集合,返回 `-1`。 - - 如果两个节点属于同一集合,则返回倍数关系。 - -## 代码 - ```python from collections import defaultdict class Solution: From 622ef7ec6b99e25329c8d28d05f5245e2b96fbd2 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sun, 8 Dec 2024 19:38:51 +0800 Subject: [PATCH 15/17] =?UTF-8?q?Update=20=E5=89=91=E6=8C=87=20Offer=20II?= =?UTF-8?q?=20105.=20=E5=B2=9B=E5=B1=BF=E7=9A=84=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E9=9D=A2=E7=A7=AF.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\232\204\346\234\200\345\244\247\351\235\242\347\247\257.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Solutions/\345\211\221\346\214\207 Offer II 105. \345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.md" "b/Solutions/\345\211\221\346\214\207 Offer II 105. \345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.md" index 03765059..31826cf9 100644 --- "a/Solutions/\345\211\221\346\214\207 Offer II 105. \345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.md" +++ "b/Solutions/\345\211\221\346\214\207 Offer II 105. \345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.md" @@ -40,4 +40,4 @@ class Solution: ans = max(ans, self.dfs(grid, i, j)) return ans ``` - +相当于是随机出现的多个树的叠加过程 From 4cc8039b537c27afd02960daf35f9d9e7914a544 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Sun, 8 Dec 2024 20:00:11 +0800 Subject: [PATCH 16/17] =?UTF-8?q?Update=20=E5=89=91=E6=8C=87=20Offer=20II?= =?UTF-8?q?=20105.=20=E5=B2=9B=E5=B1=BF=E7=9A=84=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E9=9D=A2=E7=A7=AF.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...00\345\244\247\351\235\242\347\247\257.md" | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git "a/Solutions/\345\211\221\346\214\207 Offer II 105. \345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.md" "b/Solutions/\345\211\221\346\214\207 Offer II 105. \345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.md" index 31826cf9..5d65f1fa 100644 --- "a/Solutions/\345\211\221\346\214\207 Offer II 105. \345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.md" +++ "b/Solutions/\345\211\221\346\214\207 Offer II 105. \345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.md" @@ -40,4 +40,33 @@ class Solution: ans = max(ans, self.dfs(grid, i, j)) return ans ``` -相当于是随机出现的多个树的叠加过程 +相当于是随机出现的多个树的叠加过程,下面进一步介绍dfs + +```python +def dfs(graph,node,visited=None): + if visited is None: + visited = set() + visited.add(node) # 管理是否已经经历过了 + print(node) # 对节点过程进行操作 + for neighbor in graph[node]: # 保证回溯能力 + if neighbor not in visited: + dfs(graph,neighbor,visited) # 保证继续挖的能力 + + +# 示例图 +graph = { + 'A': ['B', 'C'], + 'B': ['A', 'D', 'E'], + 'C': ['A', 'F'], + 'D': ['B'], + 'E': ['B'], + 'F': ['C'] +} + +dfs(graph, 'A') +``` + + + + + From 3dd22eefcf1f8b236fc8367e30bd931a32ada338 Mon Sep 17 00:00:00 2001 From: Exuberant Witness Date: Mon, 20 Jan 2025 16:05:45 +0800 Subject: [PATCH 17/17] =?UTF-8?q?Update=200001.=20=E4=B8=A4=E6=95=B0?= =?UTF-8?q?=E4=B9=8B=E5=92=8C.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...44\346\225\260\344\271\213\345\222\214.md" | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git "a/Solutions/0001. \344\270\244\346\225\260\344\271\213\345\222\214.md" "b/Solutions/0001. \344\270\244\346\225\260\344\271\213\345\222\214.md" index c1b4d889..31684c89 100644 --- "a/Solutions/0001. \344\270\244\346\225\260\344\271\213\345\222\214.md" +++ "b/Solutions/0001. \344\270\244\346\225\260\344\271\213\345\222\214.md" @@ -72,16 +72,36 @@ class Solution: ### 思路 2:代码 ```python -def twoSum(self, nums: List[int], target: int) -> List[int]: - numDict = dict() - for i in range(len(nums)): - if target-nums[i] in numDict: - return numDict[target-nums[i]], i - numDict[nums[i]] = i - return [0] +from typing import List + +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + # 创建一个空的哈希表,存储数值与其对应的下标 + numDict = dict() + + # 遍历数组 + for i in range(len(nums)): + # 如果目标值减去当前数(target - nums[i])在哈希表中 + # 说明找到了两数之和等于目标值,返回这两个数的下标 + if target - nums[i] in numDict: + return [numDict[target - nums[i]], i] + + # 如果没有找到,就把当前数的值和下标存入哈希表 + numDict[nums[i]] = i + + # 如果没有找到符合条件的答案,返回一个空数组(题目保证有解,这行代码理论上不会执行) + return [] + +# 创建 Solution 类的实例 +solution = Solution() + +# 调用实例方法 +nums = [2, 11, 15, 7] +target = 9 +print(solution.twoSum(nums, target)) ``` ### 思路 2:复杂度分析 - **时间复杂度**:$O(n)$,其中 $n$ 是数组 $nums$ 的元素数量。 -- **空间复杂度**:$O(n)$。 \ No newline at end of file +- **空间复杂度**:$O(n)$。