diff --git a/README.md b/README.md index 13f81e75..c026d9ca 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,14 @@ 3、 [剑指 offer](https://leetcode-cn.com/problemset/lcof/) +[剑指offer题解 Python 1](https://zhuanlan.zhihu.com/p/75864673) + +[剑指offer题解 Python 2](https://zhuanlan.zhihu.com/p/74641093) + +[剑指offer题解 Python 3](https://zhuanlan.zhihu.com/p/112990684) + +[剑指offer题解](https://darktiantian.github.io/%E5%89%91%E6%8C%87Offer/) + ![剑指offer](https://img.fuiboom.com/img/leetcode_jzoffer.png) 刷题时间可以合理分配,如果打算准备面试了,建议前面两部分 一个半月 (6 周)时间刷完,最后剑指 offer 半个月刷完,边刷可以边投简历进行面试,遇到不会的不用着急,往模板上套就对了,如果面试官给你提示,那就好好做,不要错过这大好机会~ diff --git a/advanced_algorithm/backtrack.md b/advanced_algorithm/backtrack.md index 9506cb3b..f43982b3 100644 --- a/advanced_algorithm/backtrack.md +++ b/advanced_algorithm/backtrack.md @@ -55,6 +55,19 @@ class Solution: return result ``` +```Python +class Solution: + def subsets(self, nums: List[int]) -> List[List[int]]: + result = [] + def helper(start, subset): + result.append(subset) + for i in range(start, len(nums)): + if nums[i] not in subset: + helper(i+1, subset+[nums[i]]) + helper(0, []) + return result +``` + ### [subsets-ii](https://leetcode-cn.com/problems/subsets-ii/) > 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。说明:解集不能包含重复的子集。 @@ -88,6 +101,21 @@ class Solution: return result ``` +```Python +class Solution: + def subsetsWithDup(self, nums: List[int]) -> List[List[int]]: + result = [] + length = len(nums) + nums.sort() + def helper(lst, start): + if lst not in result: + result.append(lst) + for i in range(start, length): + helper(lst+[nums[i]], i+1) + helper([], 0) + return result +``` + ### [permutations](https://leetcode-cn.com/problems/permutations/) > 给定一个没有重复数字的序列,返回其所有可能的全排列。 @@ -145,6 +173,22 @@ class Solution: return result ``` +```Python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + result = [] + length = len(nums) + def helper(lst): + if lst not in result and len(lst) == length: + result.append(lst) + else: + for i in range(length): + if nums[i] not in lst: + helper(lst+[nums[i]]) + helper([]) + return result +``` + ### [permutations-ii](https://leetcode-cn.com/problems/permutations-ii/) > 给定一个可包含重复数字的序列,返回所有不重复的全排列。 @@ -182,6 +226,21 @@ class Solution: return result ``` +```Python +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + result = [] + length = len(nums) + def helper(lst, all_lst): + if len(lst) == length and lst not in result: + result.append(lst) + else: + for i in range(len(all_lst)): + helper(lst+[all_lst[i]], all_lst[:i] + all_lst[i+1:]) + helper([], nums) + return result +``` + ### [combination-sum](https://leetcode-cn.com/problems/combination-sum/) ```Python @@ -212,6 +271,21 @@ class Solution: return result ``` +```Python +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + result = [] + length = len(candidates) + def helper(start, lst, total): + if total == target: + result.append(lst) + elif total < target: + for i in range(start, length): + helper(i, lst+[candidates[i]], total+candidates[i]) + helper(0, [], 0) + return result +``` + ### [letter-combinations-of-a-phone-number](https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/) ```Python @@ -251,6 +325,31 @@ class Solution: return result ``` +```Python +class Solution: + def letterCombinations(self, digits: str) -> List[str]: + num2char = { + '2': ['a', 'b', 'c'], + '3': ['d', 'e', 'f'], + '4': ['g', 'h', 'i'], + '5': ['j', 'k', 'l'], + '6': ['m', 'n', 'o'], + '7': ['p', 'q', 'r', 's'], + '8': ['t', 'u', 'v'], + '9': ['w', 'x', 'y', 'z'] + } + result = [] + length = len(candidates) + def helper(start, lst, total): + if total == target: + result.append(lst) + elif total < target: + for i in range(start, length): + helper(i, lst+[candidates[i]], total+candidates[i]) + helper(0, "", 0) + return result +``` + ### [palindrome-partitioning](https://leetcode-cn.com/problems/palindrome-partitioning/) ```Python @@ -324,7 +423,6 @@ class Solution: ``` - ## 练习 - [ ] [subsets](https://leetcode-cn.com/problems/subsets/) diff --git a/advanced_algorithm/binary_search_tree.md b/advanced_algorithm/binary_search_tree.md index d0399e45..9f7f3340 100644 --- a/advanced_algorithm/binary_search_tree.md +++ b/advanced_algorithm/binary_search_tree.md @@ -32,6 +32,25 @@ class Solution: return True ``` +```Python +class Solution: + def isValidBST(self, root: TreeNode) -> bool: + if not root: + return True + pre = float("-inf") + stack = [] + while root or stack: + while root: + stack.append(root) + root = root.left + root = stack.pop() + if pre >= root.val: + return False + pre = root.val + root = root.right + return True +``` + ### [insert-into-a-binary-search-tree](https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/) > 给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 保证原始二叉搜索树中不存在新值。 @@ -51,6 +70,27 @@ class Solution: return root ``` +```Python +class Solution: + def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode: + if not root: + return TreeNode(val) + node = root + while 1: + if val > root.val: + if root.right: + root = root.right + else: + root.right = TreeNode(val) + return node + else: + if root.left: + root = root.left + else: + root.left = TreeNode(val) + return node +``` + ### [delete-node-in-a-bst](https://leetcode-cn.com/problems/delete-node-in-a-bst/) > 给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的  key  对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。 @@ -97,6 +137,28 @@ class Solution: return dummy.left ``` +```Python +class Solution: + def deleteNode(self, root: TreeNode, key: int) -> TreeNode: + if not root: + return root + if key > root.val: + root.right = self.deleteNode(root.right, key) + elif key < root.val: + root.left = self.deleteNode(root.left, key) + elif key == root.val: + if not root.left: + return root.right + if not root.right: + return root.left + cur = root.right + while cur.left: + cur = cur.left + cur.left = root.left + return root.right + return root +``` + ### [balanced-binary-tree](https://leetcode-cn.com/problems/balanced-binary-tree/) > 给定一个二叉树,判断它是否是高度平衡的二叉树。 @@ -134,6 +196,22 @@ class Solution: return True ``` +```Python +class Solution: + def isBalanced(self, root: TreeNode) -> bool: + result = [True] + def helper(root): + if not root: + return 0 + left = helper(root.left) + right = helper(root.right) + if abs(left-right) > 1: + result[-1] = False + return max(left, right) + 1 + _ = helper(root) + return result[-1] +``` + ### [valid-bfs-of-bst](./bst_bfs.py) > 给定一个整数数组,求问此数组是不是一个 BST 的 BFS 顺序。 diff --git a/advanced_algorithm/recursion.md b/advanced_algorithm/recursion.md index dd1b2c46..921a7ad6 100644 --- a/advanced_algorithm/recursion.md +++ b/advanced_algorithm/recursion.md @@ -28,6 +28,18 @@ class Solution: return ``` +```Python +class Solution: + def reverseString(self, s: List[str]) -> None: + """ + Do not return anything, modify s in-place instead. + """ + mid = len(s) // 2 + for i in range(mid): + s[i], s[-i-1] = s[-i-1], s[i] + return s +``` + ### [swap-nodes-in-pairs](https://leetcode-cn.com/problems/swap-nodes-in-pairs/) > 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 @@ -47,6 +59,18 @@ class Solution: return head ``` +```Python +class Solution: + def swapPairs(self, head: ListNode) -> ListNode: + if head and head.next: + next_pair = self.swapPairs(head.next.next) + temp = head.next + head.next = next_pair + temp.next = head + head = temp + return head +``` + ### [unique-binary-search-trees-ii](https://leetcode-cn.com/problems/unique-binary-search-trees-ii/) > 给定一个整数 n,生成所有由 1 ... n 为节点所组成的二叉搜索树。 @@ -76,6 +100,25 @@ class Solution: return generateTrees_rec(1, n) if n > 0 else [] ``` +```Python +class Solution: + def generateTrees(self, n: int) -> List[TreeNode]: + if not n: + return [] + def helper(i, j): + if i > j: + return [None] + result = [] + for m in range(i, j+1): + left = helper(i, m-1) + right = helper(m+1, j) + for l in left: + for r in right: + result.append(TreeNode(m, l, r)) + return result + return helper(1, n) +``` + ## 递归 + 备忘录 (recursion with memorization, top-down DP) ### [fibonacci-number](https://leetcode-cn.com/problems/fibonacci-number/) @@ -101,6 +144,17 @@ class Solution: return fib_rec(N) ``` +```Python +class Solution: + def fib(self, n: int) -> int: + if not n: + return 0 + first, second = 0, 1 + for i in range(2, n+1): + first, second = second, first + second + return second +``` + ## 练习 - [ ] [reverse-string](https://leetcode-cn.com/problems/reverse-string/) diff --git a/advanced_algorithm/slide_window.md b/advanced_algorithm/slide_window.md index dc6acd80..ad205541 100644 --- a/advanced_algorithm/slide_window.md +++ b/advanced_algorithm/slide_window.md @@ -131,6 +131,41 @@ class Solution: return False ``` +```Python +class Solution: + def checkInclusion(self, s1: str, s2: str) -> bool: + target = collections.defaultdict(int) + + for c in s1: + target[c] += 1 + + r, num_char = 0, len(target) + + while r < len(s2): + if s2[r] in target: + l, count = r, 0 + window = collections.defaultdict(int) + while r < len(s2): + c = s2[r] + if c not in target: + break + window[c] += 1 + if window[c] == target[c]: + count += 1 + if count == num_char: + return True + while window[c] > target[c]: + window[s2[l]] -= 1 + if window[s2[l]] == target[s2[l]] - 1: + count -= 1 + l += 1 + r += 1 + else: + r += 1 + + return False +``` + ### [find-all-anagrams-in-a-string](https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/) > 给定一个字符串  **s **和一个非空字符串  **p**,找到  **s **中所有是  **p **的字母异位词的子串,返回这些子串的起始索引。 @@ -175,6 +210,40 @@ class Solution: return results ``` +```Python +class Solution: + def findAnagrams(self, s: str, p: str) -> List[int]: + w_dict = {} + n_dict = {} + for p_s in p: + if p_s not in n_dict: + n_dict[p_s] = 1 + w_dict[p_s] = 0 + else: + n_dict[p_s] += 1 + p_len = len(p) + s_len = len(s) + left = 0 + right = 0 + result = [] + while (left+p_len-1) <= s_len and right <= (s_len-1): + new_s = s[right] + if not new_s in n_dict: + right += 1 + for w_s in w_dict: + w_dict[w_s] = 0 + left = right + else: + w_dict[new_s] += 1 + if (right-left+1) == p_len: + if w_dict == n_dict: + result.append(left) + w_dict[s[left]] -= 1 + left += 1 + right += 1 + return result +``` + ### [longest-substring-without-repeating-characters](https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/) > 给定一个字符串,请你找出其中不含有重复字符的   最长子串   的长度。 @@ -200,6 +269,28 @@ class Solution: return max(max_length, len(s) - l) # note that the last substring is not judged in the loop ``` +```Python +class Solution: + def lengthOfLongestSubstring(self, s: str) -> int: + windows = {} + length = len(s) + left, right = 0, 0 + output = 0 + while left < length and right < length: + if s[right] not in windows: + windows[s[right]] = 1 + else: + windows[s[right]] += 1 + while windows[s[right]] > 1: + windows[s[left]] -= 1 + left += 1 + current = sum(windows.values()) + if current > output: + output = current + right += 1 + return output +``` + ## 总结 - 和双指针题目类似,更像双指针的升级版,滑动窗口核心点是维护一个窗口集,根据窗口集来进行处理 diff --git a/basic_algorithm/binary_search.md b/basic_algorithm/binary_search.md index 83b50904..2fbe498f 100644 --- a/basic_algorithm/binary_search.md +++ b/basic_algorithm/binary_search.md @@ -78,6 +78,26 @@ class Solution: return -1 ``` +```Python +class Solution: + def search(self, nums: List[int], target: int) -> int: + if not nums: + return -1 + start = 0 + end = len(nums) - 1 + while start + 1 < end: + mid = (start + end) // 2 + if nums[mid] < target: + start = mid + else: + end = mid + if nums[start] == target: + return start + if nums[end] == target: + return end + return -1 +``` + ## 常见题目 ### [find-first-and-last-position-of-element-in-sorted-array](https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/) @@ -158,6 +178,41 @@ class Solution: return Range ``` +```Python +class Solution: + def searchRange(self, nums: List[int], target: int) -> List[int]: + result = [-1, -1] + if not nums: + return result + start = 0 + end = len(nums) - 1 + while start + 1 < end: + mid = (start + end) // 2 + if nums[mid] < target: + start = mid + else: + end = mid + if nums[start] == target: + result[0] = start + elif nums[end] == target: + result[0] = end + else: + return result + start = 0 + end = len(nums) - 1 + while start + 1 < end: + mid = (start + end) // 2 + if nums[mid] <= target: + start = mid + else: + end = mid + if nums[start] == target: + result[1] = start + if nums[end] == target: + result[1] = end + return result +``` + ### [search-insert-position](https://leetcode-cn.com/problems/search-insert-position/) > 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 @@ -182,6 +237,28 @@ class Solution: return l ``` +```Python +class Solution: + def searchInsert(self, nums: List[int], target: int) -> int: + if not nums: + return 0 + start = 0 + end = len(nums) - 1 + while start + 1 < end: + mid = (start + end) // 2 + if nums[mid] < target: + start = mid + else: + end = mid + if target <= nums[start]: + return start + if target <= nums[end]: + return end + if target > nums[end]: + return end + 1 + return 0 +``` + ### [search-a-2d-matrix](https://leetcode-cn.com/problems/search-a-2d-matrix/) > 编写一个高效的算法来判断  m x n  矩阵中,是否存在一个目标值。该矩阵具有如下特性: @@ -224,6 +301,32 @@ class Solution: return False ``` +```Python +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + l, r = 0, len(matrix) - 1 + while l <= r: + mid = l + (r - l) // 2 + if matrix[mid][0] == target: + return True + elif matrix[mid][0] < target: + l = mid + 1 + else: + r = mid - 1 + row = r + l, r = 0, len(matrix[0]) - 1 + while l <= r: + mid = l + (r - l) // 2 + if matrix[row][mid] == target: + return True + elif matrix[row][mid] < target: + l = mid + 1 + else: + r = mid - 1 + + return False +``` + ### [find-minimum-in-rotated-sorted-array](https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/) > 假设按照升序排序的数组在预先未知的某个点上进行了旋转,例如,数组 [0, 1, 2, 4, 5, 6, 7] 可能变为 [4, 5, 6, 7, 0, 1, 2]。请找出其中最小的元素。假设数组中无重复元素。 @@ -246,6 +349,23 @@ class Solution: return nums[l] ``` +```Python +class Solution: + def findMin(self, nums: List[int]) -> int: + start = 0 + end = len(nums) - 1 + while start + 1 < end: + mid = (start + end) // 2 + if nums[end] < nums[mid]: + start = mid + else: + end = mid + if nums[start] < nums[end]: + return nums[start] + else: + return nums[end] +``` + ### [find-minimum-in-rotated-sorted-array-ii](https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/) > 假设按照升序排序的数组在预先未知的某个点上进行了旋转,例如,数组 [0, 1, 2, 4, 5, 6, 7] 可能变为 [4, 5, 6, 7, 0, 1, 2]。请找出其中最小的元素。数组中可能包含重复元素。 @@ -268,6 +388,27 @@ class Solution: return nums[l] ``` +```Python +class Solution: + def findMin(self, nums: List[int]) -> int: + start = 0 + end = len(nums) - 1 + while start + 1 < end: + while start < end and nums[end] == nums[end-1]: + end -= 1 + while start < end and nums[start] == nums[start+1]: + start += 1 + mid = (start + end) // 2 + if nums[mid] >= nums[end]: + start = mid + else: + end = mid + if nums[start] < nums[end]: + return nums[start] + else: + return nums[end] +``` + ### [search-in-rotated-sorted-array](https://leetcode-cn.com/problems/search-in-rotated-sorted-array/) > 假设按照升序排序的数组在预先未知的某个点上进行了旋转,例如,数组 [0, 1, 2, 4, 5, 6, 7] 可能变为 [4, 5, 6, 7, 0, 1, 2]。搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回  -1。假设数组中不存在重复的元素。 @@ -295,6 +436,30 @@ class Solution: return -1 ``` +```Python +class Solution: + def search(self, nums: List[int], target: int) -> int: + start = 0 + end = len(nums) - 1 + while start + 1 < end: + mid = (start + end) // 2 + if nums[start] < nums[mid]: + if nums[start] <= target <= nums[mid]: + end = mid + else: + start = mid + else: + if nums[mid] <= target <= nums[end]: + start = mid + else: + end = mid + if nums[start] == target: + return start + if nums[end] == target: + return end + return -1 +``` + ### [search-in-rotated-sorted-array-ii](https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/) > 假设按照升序排序的数组在预先未知的某个点上进行了旋转,例如,数组 [0, 0, 1, 2, 2, 5, 6] 可能变为 [2, 5, 6, 0, 0, 1, 2]。编写一个函数来判断给定的目标值是否存在于数组中,若存在返回  true,否则返回  false。数组中可能包含重复元素。 @@ -326,6 +491,37 @@ class Solution: return False ``` +```Python +class Solution: + def search(self, nums: List[int], target: int) -> bool: + start = 0 + end = len(nums) - 1 + while start + 1 < end: + while start < end and nums[end] == nums[end-1]: + end -= 1 + while start < end and nums[start] == nums[start+1]: + start += 1 + if end - start < 2: + break + middle = (start+end) // 2 + if target == nums[middle]: + return True + if nums[start] < nums[middle]: + if nums[start] <= target < nums[middle]: + end = middle + else: + start = middle + else: + if nums[middle] < target <= nums[end]: + start = middle + else: + end = middle + if nums[start] == target or nums[end] == target: + return True + else: + return False +``` + ## 隐含的二分搜索 有时用到二分搜索的题目并不会直接给你一个有序数组,它隐含在题目中,需要你去发现或者构造。一类常见的隐含的二分搜索的问题是求某个有界数据的最值,以最小值为例,当数据比最小值大时都符合条件,比最小值小时都不符合条件,那么符合/不符合条件就构成了一种有序关系,再加上数据有界,我们就可以使用二分搜索来找数据的最小值。注意,数据的界一般也不会在题目中明确提示你,需要你自己去发现。 @@ -348,6 +544,23 @@ class Solution: return l ``` +```Python +class Solution: + def minEatingSpeed(self, piles: List[int], h: int) -> int: + start = 1 + end = max(piles) + while start < end: + mid = (start + end) // 2 + time = 0 + for p in piles: + time += (p + mid - 1) // mid + if time > h: + start = mid + 1 + else: + end = mid + return start +``` + ## 总结 二分搜索核心四点要素(必背&理解) diff --git a/basic_algorithm/dp.md b/basic_algorithm/dp.md index 3b556b63..4ed13a70 100644 --- a/basic_algorithm/dp.md +++ b/basic_algorithm/dp.md @@ -79,6 +79,23 @@ class Solution: return min(dp) ``` +```Python +class Solution: + def minimumTotal(self, triangle: List[List[int]]) -> int: + result = triangle + count = 0 + for line in result: + line[0] += count + count = line[0] + for i in range(1, len(triangle)): + for j in range(1, len(triangle[i])): + if j >= len(triangle[i-1]): + result[i][j] += result[i-1][j-1] + else: + result[i][j] += min(result[i-1][j-1], result[i-1][j]) + return min(result[-1]) +``` + ## 递归和动规关系 递归是一种程序的实现方式:函数的自我调用 @@ -162,6 +179,22 @@ class Solution: return dp[-1] ``` +```Python +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + m = len(grid) + n = len(grid[0]) + result = grid + for i in range(1, m): + result[i][0] += result[i-1][0] + for j in range(1, n): + result[0][j] += result[0][j-1] + for i in range(1, m): + for j in range(1, n): + result[i][j] += min(result[i-1][j], result[i][j-1]) + return result[-1][-1] +``` + ### [unique-paths](https://leetcode-cn.com/problems/unique-paths/) > 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 @@ -184,6 +217,16 @@ class Solution: return dp[-1] ``` +```Python +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + result = [[1] * n for _ in range(m)] + for i in range(1, m): + for j in range(1, n): + result[i][j] = result[i-1][j] + result[i][j-1] + return result[-1][-1] +``` + ### [unique-paths-ii](https://leetcode-cn.com/problems/unique-paths-ii/) > 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 @@ -210,6 +253,31 @@ class Solution: return dp[-1] ``` +```Python +class Solution: + def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int: + if obstacleGrid[0][0]: + return 0 + m = len(obstacleGrid) + n = len(obstacleGrid[0]) + result = [[0] * n for _ in range(m)] + result[0][0] = 1 + for i in range(1, m): + if not obstacleGrid[i][0]: + result[i][0] = result[i-1][0] + for j in range(1, n): + if not obstacleGrid[0][j]: + result[0][j] = result[0][j-1] + + for i in range(1, m): + for j in range(1, n): + if obstacleGrid[i][j]: + result[i][j] = 0 + else: + result[i][j] = result[i-1][j] + result[i][j-1] + return result[-1][-1] +``` + ## 2、序列类型(40%) ### [climbing-stairs](https://leetcode-cn.com/problems/climbing-stairs/) @@ -229,6 +297,18 @@ class Solution: return step1 ``` +```Python +class Solution: + def climbStairs(self, n: int) -> int: + if n == 1: + return n + result = [1] * n + result[1] = 2 + for i in range(2, n): + result[i] = result[i-1] + result[i-2] + return result[-1] +``` + ### [jump-game](https://leetcode-cn.com/problems/jump-game/) > 给定一个非负整数数组,你最初位于数组的第一个位置。 @@ -265,6 +345,19 @@ class Solution: return True ``` +```Python +class Solution: + def canJump(self, nums: List[int]) -> bool: + max_jump = 0 + length = len(nums) + for i in range(length): + if max_jump >= i: + max_jump = max(max_jump, i + nums[i]) + if max_jump >= length - 1: + return True + return False +``` + ### [jump-game-ii](https://leetcode-cn.com/problems/jump-game-ii/) > 给定一个非负整数数组,你最初位于数组的第一个位置。 @@ -293,6 +386,18 @@ class Solution: return min_step ``` +```Python +class Solution: + def jump(self, nums: List[int]) -> int: + max_jump, step, end = 0, 0, 0 + for i in range(len(nums)-1): + max_jump = max(max_jump, i+nums[i]) + if i == end: + step += 1 + end = max_jump + return step +``` + ### [palindrome-partitioning-ii](https://leetcode-cn.com/problems/palindrome-partitioning-ii/) > 给定一个字符串 _s_,将 _s_ 分割成一些子串,使每个子串都是回文串。 @@ -330,10 +435,42 @@ class Solution: return dp_min[-1] ``` +```Python +class Solution: + def minCut(self, s: str) -> int: + n = len(s) + if n < 2: + return 0 + result = [n] * n + result[0] = 0 + for i in range(1, n): + if s[:i+1] == s[:i+1][::-1]: + result[i] = 0 + continue + for j in range(i): + if s[j+1:i+1] == s[j+1:i+1][::-1]: + result[i] = min(result[i], result[j]+1) + return result[-1] +``` + ### [longest-increasing-subsequence](https://leetcode-cn.com/problems/longest-increasing-subsequence/) > 给定一个无序的整数数组,找到其中最长上升子序列的长度。 +子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 +示例 1: +输入:nums = [10,9,2,5,3,7,101,18] +输出:4 +解释:最长递增子序列是 [2,3,7,101],因此长度为 4 + +示例 2: +输入:nums = [0,1,0,3,2,3] +输出:4 + +示例 3: +输入:nums = [7,7,7,7,7,7,7] +输出:1 + - DP(i) 等于以第i个数结尾的最长上升子序列的长度,容易想但不是最优 ```Python class Solution: @@ -369,6 +506,23 @@ class Solution: return len(seq) ``` +```Python +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + result = [nums[0]] + length = len(nums) + for i in range(1, length): + if nums[i] > result[-1]: + result.append(nums[i]) + continue + if nums[i] < result[-1]: + for j in range(len(result)): + if nums[i] <= result[j]: + result[j] = nums[i] + break + return len(result) +``` + ### [word-break](https://leetcode-cn.com/problems/word-break/) > 给定一个**非空**字符串  *s*  和一个包含**非空**单词列表的字典  *wordDict*,判定  *s*  是否可以被空格拆分为一个或多个在字典中出现的单词。 @@ -390,6 +544,22 @@ class Solution: ``` +```Python +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + length = len(s) + result = [False] * length + for i in range(length): + if s[:i+1] in wordDict: + result[i] = True + continue + for j in range(i+1): + if result[j] and s[j+1:i+1] in wordDict: + result[i] = True + break + return result[-1] +``` + 小结 常见处理方式是给 0 位置占位,这样处理问题时一视同仁,初始化则在原来基础上 length+1,返回结果 f[n] @@ -437,6 +607,21 @@ class Solution: return dp[-1] ``` +```Python +class Solution: + def longestCommonSubsequence(self, text1: str, text2: str) -> int: + m = len(text1) + 1 + n = len(text2) + 1 + result = [[0]*n for _ in range(m)] + for i in range(1, m): + for j in range(1, n): + if text1[i-1] == text2[j-1]: + result[i][j] = result[i-1][j-1] + 1 + else: + result[i][j] = max(result[i-1][j], result[i][j-1]) + return result[-1][-1] +``` + ### [edit-distance](https://leetcode-cn.com/problems/edit-distance/) > 给你两个单词  word1 和  word2,请你计算出将  word1  转换成  word2 所使用的最少操作数   @@ -476,6 +661,28 @@ class Solution: return dp[-1] ``` +```Python +class Solution: + def minDistance(self, word1: str, word2: str) -> int: + m = len(word1) + n = len(word2) + if not m*n: + return m+n + m, n = m + 1, n + 1 + result = [[0]*n for _ in range(m)] + for i in range(m): + result[i][0] = i + for j in range(n): + result[0][j] = j + for i in range(1, m): + for j in range(1, n): + if word1[i-1] == word2[j-1]: + result[i][j] = result[i-1][j-1] + else: + result[i][j] = min(result[i-1][j-1], result[i-1][j], result[i][j-1]) + 1 + return result[-1][-1] +``` + 说明 > 另外一种做法:MAXLEN(a,b)-LCS(a,b) @@ -504,6 +711,19 @@ class Solution: return -1 if dp[amount] == float('inf') else dp[amount] ``` +```Python +class Solution: + def coinChange(self, coins: List[int], amount: int) -> int: + result = [float("inf")] * (amount+1) + result[0] = 0 + for i in range(1, amount+1): + for j in range(len(coins)): + if i >= coins[j]: + result[i] = min(result[i], result[i-coins[j]]+1) + if result[-1] == float("inf"): + return -1 + return result[-1] +``` ### [backpack](https://www.lintcode.com/problem/backpack/description) @@ -529,6 +749,35 @@ class Solution: ``` +```Python +def backPack(weight, value, bagweight): + # 二维数组 + dp = [[0] * (bagweight + 1) for _ in range(len(weight))] + + # 初始化 + for j in range(weight[0], bagweight + 1): + dp[0][j] = value[0] + + # weight数组的大小就是物品个数 + for i in range(1, len(weight)): # 遍历物品 + for j in range(bagweight + 1): # 遍历背包容量 + if j < weight[i]: + dp[i][j] = dp[i - 1][j] + else: + dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]) + + return dp[len(weight) - 1][bagweight] + +if __name__ == "__main__": + + weight = [1, 3, 4] + value = [15, 20, 30] + bagweight = 4 + + result = backPack(weight, value, bagweight) + print(result) +``` + ### [backpack-ii](https://www.lintcode.com/problem/backpack-ii/description) > 有 `n` 个物品和一个大小为 `m` 的背包. 给定数组 `A` 表示每个物品的大小和数组 `V` 表示每个物品的价值. @@ -556,6 +805,10 @@ class Solution: ``` +```Python + +``` + ## 补充 ### [maximum-product-subarray](https://leetcode-cn.com/problems/maximum-product-subarray/) @@ -588,6 +841,10 @@ class Solution: return max_product ``` +```Python + +``` + ### [decode-ways](https://leetcode-cn.com/problems/decode-ways/) > 1 到 26 分别对应 a 到 z,给定输入数字串,问总共有多少种译码方法 @@ -611,6 +868,10 @@ class Solution: return dp_1 ``` +```Python + +``` + ### [best-time-to-buy-and-sell-stock-with-cooldown](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) > 给定股票每天的价格,每天可以买入卖出,买入后必须卖出才可以进行下一次购买,卖出后一天不可以购买,问可以获得的最大利润 @@ -629,6 +890,23 @@ class Solution: return max(buy, buy_then_nothing, sell, sell_then_nothing) ``` +```Python +class Solution: + def maxProfit(self, prices: List[int]) -> int: + n = len(prices) + if n < 2: + return 0 + buy = [0] * n + sell = [0] * n + sell_s = [0] * n + buy[0] = -prices[0] + for i in range(1, n): + buy[i] = max(buy[i-1], sell[i-1] - prices[i]) + sell_s[i] = buy[i-1] + prices[i] + sell[i] = max(sell_s[i-1], sell[i-1]) + return max(sell[-1], sell_s[-1]) +``` + ### [word-break-ii](https://leetcode-cn.com/problems/word-break-ii/) > 给定字符串和可选的单词列表,求字符串所有的分割方式 @@ -671,6 +949,10 @@ class Solution: return result ``` +```Python + +``` + ### [burst-balloons](https://leetcode-cn.com/problems/burst-balloons/) > n 个气球排成一行,每个气球上有一个分数,每次戳爆一个气球得分为该气球分数和相邻两气球分数的乘积,求最大得分 @@ -697,6 +979,168 @@ class Solution: return dp[-1][n] ``` +### [best-time-to-buy-and-sell-stock](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/) +121. 买卖股票的最佳时机 +给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 + +只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 + +返回可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。 + +```Python +class Solution: + def maxProfit(self, prices: List[int]) -> int: + buy = float("inf") + sell = 0 + for day in prices: + buy = min(buy, day) + sell = max(sell, day - buy) + return sell +``` + +### [best-time-to-buy-and-sell-stock-ii](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/) +122. 买卖股票的最佳时机 II +给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。 + +设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 + +注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + +```Python +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + length = len(prices) + dp = [[0,0] for _ in range(length)] + dp[0][0] = 0 + dp[0][1] = -prices[0] + for i in range(1, length): + dp[i][0] = max(dp[i-1][0],dp[i-1][1] + prices[i]) + dp[i][1] = max(dp[i-1][0]-prices[i],dp[i-1][1]) + return max(dp[-1][0],dp[-1][1]) +``` + +```Python +class Solution: + def maxProfit(self, prices: List[int]) -> int: + profit = 0 + for i in range(1, len(prices)): + tmp = prices[i] - prices[i - 1] + if tmp > 0: profit += tmp + return profit +``` + + +### [best-time-to-buy-and-sell-stock-iii](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/) + +123. 买卖股票的最佳时机 III +给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。 + +设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 + +注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + + +```Python +class Solution: + def maxProfit(self, prices: List[int]) -> int: + n = len(prices) + buy1 = buy2 = -prices[0] + sell1 = sell2 = 0 + for i in range(1, n): + buy1 = max(buy1, -prices[i]) + sell1 = max(sell1, buy1 + prices[i]) + buy2 = max(buy2, sell1 - prices[i]) + sell2 = max(sell2, buy2 + prices[i]) + return sell2 +``` + + +### [best-time-to-buy-and-sell-stock-iv](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/) + +188. 买卖股票的最佳时机 IV +给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。 + +设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。 + +注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + + +```Python +class Solution: + def maxProfit(self, k: int, prices: List[int]) -> int: + days = len(prices) + profit = 0 + if days < 2: + return profit + if k >= days: + for day in range(1, days): + if prices[day] > prices[day-1]: + profit += (prices[day] - prices[day-1]) + return profit + buy = [float("-inf")]* (k+1) + sell = [0]* (k+1) + for i in range(days): + for j in range(1, k+1): + buy[j] = max(buy[j], sell[j-1]-prices[i]) + sell[j] = max(sell[j], buy[j]+prices[i]) + return sell[-1] +``` + + +### [best-time-to-buy-and-sell-stock-with-transaction-fee](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/) + +给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。 + +你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。 + +返回获得利润的最大值。 + +注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。 + + +```Python +class Solution: + def maxProfit(self, prices: List[int], fee: int) -> int: + n = len(prices) + dp = [[0, -prices[0]]] + [[0, 0] for _ in range(n - 1)] + for i in range(1, n): + dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee) + dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]) + return dp[n - 1][0] +``` + + +### [best-time-to-buy-and-sell-stock-with-cooldown](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) + +309. 最佳买卖股票时机含冷冻期 +给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​ + +设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票): + +你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 +卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。 + + +```Python +class Solution: + def maxProfit(self, prices: List[int]) -> int: + n = len(prices) + if n < 2: + return 0 + buy = [0] * n + sell = [0] * n + sell_s = [0] * n + buy[0] = -prices[0] + for i in range(1, n): + buy[i] = max(buy[i-1], sell[i-1] - prices[i]) + sell_s[i] = buy[i-1] + prices[i] + sell[i] = max(sell_s[i-1], sell[i-1]) + return max(sell[-1], sell_s[-1]) +``` ## 练习 @@ -727,3 +1171,10 @@ Backpack & Coin Change (10%) - [ ] [coin-change](https://leetcode-cn.com/problems/coin-change/) - [ ] [backpack](https://www.lintcode.com/problem/backpack/description) - [ ] [backpack-ii](https://www.lintcode.com/problem/backpack-ii/description) + +Others +- [ ] [maximum-product-subarray](https://leetcode-cn.com/problems/maximum-product-subarray/) +- [ ] [decode-ways](https://leetcode-cn.com/problems/decode-ways/) +- [ ] [best-time-to-buy-and-sell-stock-with-cooldown](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) +- [ ] [word-break-ii](https://leetcode-cn.com/problems/word-break-ii/) +- [ ] [burst-balloons](https://leetcode-cn.com/problems/burst-balloons/) diff --git a/data_structure/binary_op.md b/data_structure/binary_op.md index eb061db0..586a76a9 100644 --- a/data_structure/binary_op.md +++ b/data_structure/binary_op.md @@ -43,6 +43,15 @@ class Solution: return out ``` +```Python +class Solution: + def singleNumber(self, nums: List[int]) -> int: + one = 0 + for n in nums: + one ^= n + return one +``` + ### [single-number-ii](https://leetcode-cn.com/problems/single-number-ii/) > 给定一个**非空**整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。 @@ -59,6 +68,17 @@ class Solution: return seen_once ``` +```Python +class Solution: + def singleNumber(self, nums: List[int]) -> int: + one, two = 0, 0 + for n in nums: + one = one ^ n & ~two + two = two ^ n & ~one + return one +``` + + ### [single-number-iii](https://leetcode-cn.com/problems/single-number-iii/) > 给定一个整数数组  `nums`,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。 @@ -83,6 +103,21 @@ class Solution: return [x, bitmask^x] ``` +```Python +class Solution: + def singleNumber(self, nums: List[int]) -> List[int]: + output = 0 + for n in nums: + output ^= n + diff = output & (-output) + x = 0 + for n in nums: + if diff & n: + x ^= n + return [x, x^output] +``` + + ### [number-of-1-bits](https://leetcode-cn.com/problems/number-of-1-bits/) > 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’  的个数(也被称为[汉明重量](https://baike.baidu.com/item/%E6%B1%89%E6%98%8E%E9%87%8D%E9%87%8F))。 @@ -97,6 +132,17 @@ class Solution: return num_ones ``` +```Python +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + while n: + count += 1 + n &= n-1 + return count +``` + + ### [counting-bits](https://leetcode-cn.com/problems/counting-bits/) > 给定一个非负整数  **num**。对于  0 ≤ i ≤ num  范围中的每个数字  i ,计算其二进制数中的 1 的数目并将它们作为数组返回。 @@ -148,6 +194,16 @@ class Solution: return num_ones ``` +```Python +class Solution: + def countBits(self, num: int) -> List[int]: + output = [0] * (num + 1) + for i in range(1, num+1): + output[i] = output[i&(i-1)] + 1 + return output +``` + + ### [reverse-bits](https://leetcode-cn.com/problems/reverse-bits/) > 颠倒给定的 32 位无符号整数的二进制位。 @@ -172,6 +228,18 @@ class Solution: return (byte * 0x0202020202 & 0x010884422010) % 1023 ``` +```Python +class Solution: + def reverseBits(self, n: int) -> int: + output = 0 + for i in range(32): + output <<= 1 + output += n & 1 + n >>= 1 + return output +``` + + ### [bitwise-and-of-numbers-range](https://leetcode-cn.com/problems/bitwise-and-of-numbers-range/) > 给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。 @@ -191,6 +259,17 @@ class Solution: return m << shift ``` +```Python +class Solution: + def rangeBitwiseAnd(self, left: int, right: int) -> int: + shift = 0 + while left < right: + left >>= 1 + right >>= 1 + shift += 1 + return left << shift +``` + ## 练习 - [ ] [single-number](https://leetcode-cn.com/problems/single-number/) @@ -199,3 +278,9 @@ class Solution: - [ ] [number-of-1-bits](https://leetcode-cn.com/problems/number-of-1-bits/) - [ ] [counting-bits](https://leetcode-cn.com/problems/counting-bits/) - [ ] [reverse-bits](https://leetcode-cn.com/problems/reverse-bits/) +- [ ] [bitwise-and-of-numbers-range](https://leetcode-cn.com/problems/bitwise-and-of-numbers-range/) + +## 参考链接 + +- [ ] [一篇读懂Python中的位运算](https://www.cnblogs.com/Neeo/articles/10536202.html) +- [ ] [只出现一次的数字 II](https://leetcode-cn.com/problems/single-number-ii/solution/single-number-ii-mo-ni-san-jin-zhi-fa-by-jin407891/) diff --git a/data_structure/binary_tree.md b/data_structure/binary_tree.md index 90bf1d18..5801524b 100644 --- a/data_structure/binary_tree.md +++ b/data_structure/binary_tree.md @@ -5,7 +5,9 @@ ### 二叉树遍历 **前序遍历**:**先访问根节点**,再前序遍历左子树,再前序遍历右子树 + **中序遍历**:先中序遍历左子树,**再访问根节点**,再中序遍历右子树 + **后序遍历**:先后序遍历左子树,再后序遍历右子树,**再访问根节点** 注意点 @@ -67,6 +69,36 @@ class Solution: return preorder ``` +```Python +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + if not root: + return [] + result = [] + stock = [] + while root or stock: + while root: + result.append(root.val) + stock.append(root) + root = root.left + root = stock.pop() + root = root.right + return result +``` + +```Python +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + def helper(root): + if root: + result.append(root.val) + helper(root.left) + helper(root.right) + helper(root) + return result +``` + #### [中序非递归](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/) ```Python @@ -85,6 +117,28 @@ class Solution: return inorder ``` +```Python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def inorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + stack = [] + while root or stack: + while root: + stack.append(root) + root = root.left + root = stack.pop() + result.append(root.val) + root = root.right + return result + +``` + #### [后序非递归](https://leetcode-cn.com/problems/binary-tree-postorder-traversal/) ```Python @@ -110,6 +164,26 @@ class Solution: return postorder ``` +```Python +class Solution: + def postorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + stack = [] + visit = None + while root or stack: + while root: + stack.append(root) + root = root.left + node = stack[-1] + if not node.right or node.right == visit: + result.append(node.val) + visit = node + stack.pop() + else: + root = node.right + return result +``` + 注意点 - 核心就是:根节点必须在右节点弹出之后,再弹出 @@ -161,6 +235,26 @@ class Solution: return levels ``` +```Python +class Solution: + def levelOrder(self, root: TreeNode) -> List[List[int]]: + result = [] + if not root: + return result + stack = collections.deque([root]) + while stack: + length = len(stack) + result.append([]) + for _ in range(length): + root = stack.popleft() + result[-1].append(root.val) + if root.left: + stack.append(root.left) + if root.right: + stack.append(root.right) + return result +``` + ### 分治法应用 先分别处理局部,再合并结果 @@ -220,6 +314,25 @@ class Solution: return depth ``` +```Python +class Solution: + def maxDepth(self, root: TreeNode) -> int: + level = 0 + if not root: + return level + stack = collections.deque([root]) + while stack: + level += 1 + length = len(stack) + for _ in range(length): + root = stack.popleft() + if root.left: + stack.append(root.left) + if root.right: + stack.append(root.right) + return level +``` + ### [balanced-binary-tree](https://leetcode-cn.com/problems/balanced-binary-tree/) > 给定一个二叉树,判断它是否是高度平衡的二叉树。 @@ -278,6 +391,22 @@ class Solution: return True ``` +```Python +class Solution: + def isBalanced(self, root: TreeNode) -> bool: + result = [True] + def helper(root): + if not root: + return 0 + left = helper(root.left) + right = helper(root.right) + if abs(left-right) > 1: + result[-1] = False + return max(left, right) + 1 + _ = helper(root) + return result[-1] +``` + ### [binary-tree-maximum-path-sum](https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/) > 给定一个**非空**二叉树,返回其最大路径和。 @@ -305,6 +434,22 @@ class Solution: return self.maxPath ``` +```Python +class Solution: + def maxPathSum(self, root: TreeNode) -> int: + self.maxPath = float("-inf") + def helper(root): + if not root: + return float("-inf") + left = helper(root.left) + right = helper(root.right) + curPath = max(left, 0) + max(right, 0) + root.val + self.maxPath = max(self.maxPath, curPath, left, right) + return max(left, right, 0) + root.val + helper(root) + return self.maxPath +``` + ### [lowest-common-ancestor-of-a-binary-tree](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/) > 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 @@ -334,6 +479,22 @@ class Solution: return None ``` +```Python +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + if root == p or root == q or not root: + return root + left = self.lowestCommonAncestor(root.left, p, q) + right = self.lowestCommonAncestor(root.right, p, q) + if left and right: + return root + if left: + return left + if right: + return right + return None +``` + ### BFS 层次应用 ### [binary-tree-zigzag-level-order-traversal](https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/) @@ -380,6 +541,33 @@ class Solution: return levels ``` +```Python +class Solution: + def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]: + result = [] + if not root: + return result + order = 1 + stack = collections.deque([root]) + while stack: + length = len(stack) + temp = [] + for _ in range(length): + root = stack.popleft() + temp.append(root.val) + if root.left: + stack.append(root.left) + if root.right: + stack.append(root.right) + if order: + result.append(temp) + order = 0 + else: + result.append(temp[::-1]) + order = 1 + return result +``` + ### 二叉搜索树应用 ### [validate-binary-search-tree](https://leetcode-cn.com/problems/validate-binary-search-tree/) @@ -440,6 +628,25 @@ class Solution: return True ``` +```Python +class Solution: + def isValidBST(self, root: TreeNode) -> bool: + if not root: + return True + pre = float("-inf") + stack = [] + while root or stack: + while root: + stack.append(root) + root = root.left + root = stack.pop() + if pre >= root.val: + return False + pre = root.val + root = root.right + return True +``` + #### [insert-into-a-binary-search-tree](https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/) > 给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 @@ -469,6 +676,26 @@ class Solution: node = node.left ``` +```Python +class Solution: + def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode: + if not root: + return TreeNode(val) + node = root + while 1: + if val > root.val: + if root.right: + root = root.right + else: + root.right = TreeNode(val) + return node + else: + if root.left: + root = root.left + else: + root.left = TreeNode(val) + return node +``` ## 总结 - 掌握二叉树递归与非递归遍历 diff --git a/data_structure/linked_list.md b/data_structure/linked_list.md index f77e707f..b411285b 100644 --- a/data_structure/linked_list.md +++ b/data_structure/linked_list.md @@ -37,6 +37,22 @@ class Solution: return head ``` +```Python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def deleteDuplicates(self, head: ListNode) -> ListNode: + start = head + while head: + while head.next and head.val == head.next.val: + head.next = head.next.next + head = head.next + return start +``` + ### [remove-duplicates-from-sorted-list-ii](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/) > 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中   没有重复出现的数字。 @@ -77,6 +93,23 @@ class Solution: • 删除用一个 Dummy Node 节点辅助(允许头节点可变) • 访问 X.next 、X.value 一定要保证 X != nil +```Python +class Solution: + def deleteDuplicates(self, head: ListNode) -> ListNode: + dummy = ListNode(0, head) + pre = dummy + while head: + cur = head.val + if head.next and cur == head.next.val: + while head and cur == head.val: + head = head.next + pre.next = head + else: + pre = head + head = head.next + return dummy.next +``` + ### [reverse-linked-list](https://leetcode-cn.com/problems/reverse-linked-list/) > 反转一个单链表。 @@ -115,6 +148,18 @@ class Solution: return rev_next ``` +```Python +class Solution: + def reverseList(self, head: ListNode) -> ListNode: + pre = None + while head: + temp = head.next + head.next = pre + pre = head + head = temp + return pre +``` + ### [reverse-linked-list-ii](https://leetcode-cn.com/problems/reverse-linked-list-ii/) > 反转从位置  *m*  到  *n*  的链表。请使用一趟扫描完成反转。 @@ -145,6 +190,32 @@ class Solution: return dummy.next ``` +```Python +class Solution: + def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode: + if not head.next: + return head + dummy = ListNode() + dummy.next = head + pre = dummy + count = 1 + while count < left: + pre = head + head = head.next + count += 1 + cur = pre + start = head + while count <= right: + temp = head.next + head.next = cur + cur = head + head = temp + count += 1 + pre.next = cur + start.next = head + return dummy.next +``` + ### [merge-two-sorted-lists](https://leetcode-cn.com/problems/merge-two-sorted-lists/) > 将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 @@ -173,6 +244,26 @@ class Solution: return dummy.next ``` +```Python +class Solution: + def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: + dummy = ListNode() + head = dummy + while l1 and l2: + if l1.val < l2.val: + head.next = l1 + l1 = l1.next + else: + head.next = l2 + l2 = l2.next + head = head.next + if l1: + head.next = l1 + if l2: + head.next = l2 + return dummy.next +``` + ### [partition-list](https://leetcode-cn.com/problems/partition-list/) > 给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于  *x*  的节点都在大于或等于  *x*  的节点之前。 @@ -204,6 +295,25 @@ class Solution: > 当头节点不确定的时候,使用哑巴节点 +```Python +class Solution: + def partition(self, head: ListNode, x: int) -> ListNode: + if not head or not head.next: + return head + s_head = s = ListNode(next=head) + l_head = l = ListNode() + while s.next: + if s.next.val < x: + s = s.next + else: + l.next = s.next + s.next = s.next.next + l = l.next + l.next = None + s.next = l_head.next + return s_head.next +``` + ### [sort-list](https://leetcode-cn.com/problems/sort-list/) > 在  *O*(*n* log *n*) 时间复杂度和常数级空间复杂度下,对链表进行排序。 @@ -257,6 +367,40 @@ class Solution: - 递归 mergeSort 需要断开中间节点 - 递归返回条件为 head 为 nil 或者 head.Next 为 nil +```Python +class Solution: + def middle(self, head): + slow, fast = head, head.next + while fast and fast.next: + slow = slow.next + fast = fast.next.next + return slow + + def merge(self, l1, l2): + head = l = ListNode() + while l1 and l2: + if l1.val < l2.val: + l.next = l1 + l1 = l1.next + else: + l.next = l2 + l2 = l2.next + l = l.next + if l1: + l.next = l1 + if l2: + l.next = l2 + return head.next + + def sortList(self, head: ListNode) -> ListNode: + if not head or not head.next: + return head + mid = self.middle(head) + sec = mid.next + mid.next = None + return self.merge(self.sortList(head), self.sortList(sec)) +``` + ### [reorder-list](https://leetcode-cn.com/problems/reorder-list/) > 给定一个单链表  *L*:*L*→*L*→…→*L\_\_n*→*L* @@ -303,6 +447,40 @@ class Solution: return ``` +```Python +class Solution: + def reorderList(self, head: ListNode) -> None: + """ + Do not return anything, modify head in-place instead. + """ + if not head or not head.next: + return head + + slow = l1 = head + fast = head.next + while fast and fast.next: + fast = fast.next.next + slow = slow.next + cur = slow.next + pre = None + slow.next = None + + while cur: + temp = cur.next + cur.next = pre + pre = cur + cur = temp + + while l1 and pre: + tpre = pre.next + pre.next = l1.next + l1.next = pre + l1 = l1.next.next + pre = tpre + + return head +``` + ### [linked-list-cycle](https://leetcode-cn.com/problems/linked-list-cycle/) > 给定一个链表,判断链表中是否有环。 @@ -326,6 +504,19 @@ class Solution: return False ``` +```Python +class Solution: + def hasCycle(self, head: ListNode) -> bool: + slow = head + fast = head + while fast and fast.next: + fast = fast.next.next + slow = slow.next + if fast == slow: + return True + return False +``` + ### [linked-list-cycle-ii](https://leetcode-cn.com/problems/linked-list-cycle-ii/) > 给定一个链表,返回链表开始入环的第一个节点。  如果链表无环,则返回  `null`。 @@ -365,6 +556,22 @@ class Solution: - fast 如果初始化为 head.Next 则中点在 slow.Next - fast 初始化为 head,则中点在 slow +```Python +class Solution: + def detectCycle(self, head: ListNode) -> ListNode: + fast = slow = head + while fast and fast.next: + fast = fast.next.next + slow = slow.next + if fast == slow: + slow = head + while fast != slow: + fast = fast.next + slow = slow.next + return slow + return None +``` + ### [palindrome-linked-list](https://leetcode-cn.com/problems/palindrome-linked-list/) > 请判断一个链表是否为回文链表。 @@ -393,6 +600,29 @@ class Solution: return True ``` +```Python +class Solution: + def isPalindrome(self, head: ListNode) -> bool: + slow = head + fast = head + while fast and fast.next: + fast = fast.next.next + slow = slow.next + pre = None + while slow: + temp = slow.next + slow.next = pre + pre = slow + slow = temp + while pre: + if head.val == pre.val: + pre = pre.next + head = head.next + else: + return False + return True +``` + ### [copy-list-with-random-pointer](https://leetcode-cn.com/problems/copy-list-with-random-pointer/) > 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。 @@ -461,6 +691,25 @@ class Solution: return new ``` +```Python +class Solution: + def copyRandomList(self, head: 'Node') -> 'Node': + if not head: + return None + copy = {} + m = n = head + while m: + copy[m] = Node(m.val) + m = m.next + while n: + if n.next: + copy[n].next = copy[n.next] + if n.random: + copy[n].random = copy[n.random] + n = n.next + return copy[head] +``` + ## 总结 链表必须要掌握的一些点,通过下面练习题,基本大部分的链表类的题目都是手到擒来~ diff --git a/data_structure/stack_queue.md b/data_structure/stack_queue.md index 036aa600..5b408582 100644 --- a/data_structure/stack_queue.md +++ b/data_structure/stack_queue.md @@ -40,6 +40,41 @@ class MinStack: return self.stack[-1][1] ``` +```Python +class MinStack: + + def __init__(self): + """ + initialize your data structure here. + """ + self.stack = [] + + + def push(self, val: int) -> None: + if self.stack: + self.stack.append([val, min(val, self.stack[-1][1])]) + else: + self.stack.append([val, val]) + + def pop(self) -> None: + self.stack.pop()[0] + + def top(self) -> int: + return self.stack[-1][0] + + def getMin(self) -> int: + return self.stack[-1][1] + + + +# Your MinStack object will be instantiated and called as such: +# obj = MinStack() +# obj.push(val) +# obj.pop() +# param_3 = obj.top() +# param_4 = obj.getMin() +``` + ### [evaluate-reverse-polish-notation](https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/) > **波兰表达式计算** > **输入:** ["2", "1", "+", "3", "*"] > **输出:** 9 @@ -78,6 +113,24 @@ class Solution: return stack[0] ``` +```Python +class Solution: + def evalRPN(self, tokens: List[str]) -> int: + stack = [] + s = ["+", "-", "*", "/"] + for t in tokens: + if t == s[0]: + t = stack.pop(-2) + stack.pop() + elif t == s[1]: + t = stack.pop(-2) - stack.pop() + elif t == s[2]: + t = stack.pop(-2) * stack.pop() + elif t == s[3]: + t = stack.pop(-2) / stack.pop() + stack.append(int(t)) + return stack[0] +``` + ### [decode-string](https://leetcode-cn.com/problems/decode-string/) > 给定一个经过编码的字符串,返回它解码后的字符串。 @@ -111,6 +164,29 @@ class Solution: return stack_str[0] ``` +```Python +class Solution: + def decodeString(self, s: str) -> str: + num = 0 + output = "" + char_stack = [""] + num_stack = [] + for i in s: + if i >= "0" and i <= "9": + num = num * 10 + int(i) + elif i == "[": + num_stack.append(num) + char_stack.append("") + num = 0 + elif i == "]": + new = char_stack.pop() * num_stack.pop() + char_stack[-1] += new + else: + char_stack[-1] += i + return char_stack[0] +``` + + ### [binary-tree-inorder-traversal](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/) > 给定一个二叉树,返回它的*中序*遍历。 @@ -136,6 +212,23 @@ class Solution: return inorder ``` + +```Python +class Solution: + def inorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + stack = [] + while root or stack: + while root: + stack.append(root) + root = root.left + root = stack.pop() + result.append(root.val) + root = root.right + return result +``` + + ### [clone-graph](https://leetcode-cn.com/problems/clone-graph/) > 给你无向连通图中一个节点的引用,请你返回该图的深拷贝(克隆)。 @@ -194,6 +287,31 @@ class Solution: return visited[start] ``` +```Python +""" +# Definition for a Node. +class Node: + def __init__(self, val = 0, neighbors = None): + self.val = val + self.neighbors = neighbors if neighbors is not None else [] +""" + +class Solution: + def cloneGraph(self, node: 'Node') -> 'Node': + if not node: + return None + deque = collections.deque([node]) + output = {node: Node(node.val, [])} + while deque: + cur = deque.popleft() + for nb in cur.neighbors: + if nb not in output: + output[nb] = Node(nb.val, []) + deque.append(nb) + output[cur].neighbors.append(output[nb]) + return output[node] +``` + ### [number-of-islands](https://leetcode-cn.com/problems/number-of-islands/) > 给定一个由  '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 @@ -238,6 +356,31 @@ class Solution: return num_island ``` +```Python +class Solution: + def numIslands(self, grid: List[List[str]]) -> int: + num = 0 + m_len = len(grid) + n_len = len(grid[0]) + lst = [-1, 0, 1, 0, -1] + + def updateGrid(m, n): + if grid[m][n] == "1": + grid[m][n] = "0" + for i in range(len(lst)-1): + new_m = m + lst[i] + new_n = n + lst[i+1] + if 0 <= new_m < m_len and 0 <= new_n < n_len: + updateGrid(new_m, new_n) + + for m in range(m_len): + for n in range(n_len): + if grid[m][n] == "1": + num += 1 + updateGrid(m, n) + return num +``` + ### [largest-rectangle-in-histogram](https://leetcode-cn.com/problems/largest-rectangle-in-histogram/) > 给定 _n_ 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 @@ -323,6 +466,21 @@ class Solution: return max_area ``` +```Python +class Solution: + def largestRectangleArea(self, heights: List[int]) -> int: + heights.append(0) + output = 0 + stack = [-1] + for i in range(len(heights)): + while len(stack) > 1 and heights[stack[-1]] > heights[i]: + h = stack.pop() + output = max(output, heights[h]*(i-stack[-1]-1)) + stack.append(i) + return output +``` + + ## Queue 队列 常用于 BFS 宽度优先搜索 @@ -370,6 +528,53 @@ class MyQueue: return len(self.cache) == 0 and len(self.out) == 0 ``` +```Python +class MyQueue: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.queue = collections.deque([]) + + def push(self, x: int) -> None: + """ + Push element x to the back of queue. + """ + self.queue.append(x) + + def pop(self) -> int: + """ + Removes the element from in front of queue and returns that element. + """ + return self.queue.popleft() + + def peek(self) -> int: + """ + Get the front element. + """ + return self.queue[0] + + def empty(self) -> bool: + """ + Returns whether the queue is empty. + """ + if self.queue: + return False + else: + return True + + + +# Your MyQueue object will be instantiated and called as such: +# obj = MyQueue() +# obj.push(x) +# param_2 = obj.pop() +# param_3 = obj.peek() +# param_4 = obj.empty() +``` + + ### [binary-tree-level-order-traversal](https://leetcode-cn.com/problems/binary-tree-level-order-traversal/) > 二叉树的层序遍历 @@ -400,6 +605,27 @@ class Solution: return levels ``` +```Python +class Solution: + def levelOrder(self, root: TreeNode) -> List[List[int]]: + result = [] + if not root: + return result + stack = collections.deque([root]) + while stack: + length = len(stack) + result.append([]) + for _ in range(length): + root = stack.popleft() + result[-1].append(root.val) + if root.left: + stack.append(root.left) + if root.right: + stack.append(root.right) + return result +``` + + ### [01-matrix](https://leetcode-cn.com/problems/01-matrix/) > 给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。 @@ -471,6 +697,36 @@ class Solution: return dist ``` +```Python +class Solution: + def updateMatrix(self, mat: List[List[int]]) -> List[List[int]]: + if len(mat) == 0 or len(mat[0]) == 0: + return mat + + m, n = len(mat), len(mat[0]) + dist = [[float('inf')] * n for _ in range(m)] + + bfs = collections.deque([]) + for i in range(m): + for j in range(n): + if mat[i][j] == 0: + dist[i][j] = 0 + bfs.append((i, j)) + + neighbors = [(-1, 0), (1, 0), (0, -1), (0, 1)] + while len(bfs) > 0: + i, j = bfs.popleft() + for dn_i, dn_j in neighbors: + n_i, n_j = i + dn_i, j + dn_j + if n_i >= 0 and n_i < m and n_j >= 0 and n_j < n: + if dist[n_i][n_j] > dist[i][j] + 1: + dist[n_i][n_j] = dist[i][j] + 1 + bfs.append((n_i, n_j)) + + return dist +``` + + ## 补充:单调栈 顾名思义,单调栈即是栈中元素有单调性的栈,典型应用为用线性的时间复杂度找左右两侧第一个大于/小于当前元素的位置。 @@ -491,6 +747,21 @@ class Solution: return result ``` +```Python +class Solution: + def largestRectangleArea(self, heights: List[int]) -> int: + heights.append(0) + output = 0 + stack = [-1] + for i in range(len(heights)): + while len(stack) > 1 and heights[stack[-1]] > heights[i]: + h = stack.pop() + output = max(output, heights[h]*(i-stack[-1]-1)) + stack.append(i) + return output +``` + + ### [trapping-rain-water](https://leetcode-cn.com/problems/trapping-rain-water/) ```Python @@ -511,6 +782,11 @@ class Solution: return result ``` +```Python + +``` + + ## 补充:单调队列 单调栈的拓展,可以从数组头 pop 出旧元素,典型应用是以线性时间获得区间最大/最小值。 @@ -549,6 +825,30 @@ class Solution: return result ``` +```Python +class Solution: + def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]: + if k == 1: + return nums + result = [] + # max index deque + max_index = collections.deque() + length = len(nums) + for i in range(length): + # max left index < current left index + if max_index and max_index[0] == i - k: + max_index.popleft() + # update new max num index + while max_index and nums[max_index[-1]] < nums[i]: + max_index.pop() + max_index.append(i) + # after k-1 index, record max number + if i >= k - 1: + result.append(nums[max_index[0]]) + return result +``` + + ### [shortest-subarray-with-sum-at-least-k](https://leetcode-cn.com/problems/shortest-subarray-with-sum-at-least-k/) ```Python @@ -575,6 +875,25 @@ class Solution: return result if result < N + 1 else -1 ``` +```Python +class Solution: + def shortestSubarray(self, nums, k): + length = len(nums) + sum_list = [0] + for num in nums: + sum_list.append(sum_list[-1] + num) + result = length + 1 + window = collections.deque() + for i, num_sum in enumerate(sum_list): + # remove num <= 0, [84,-37,32,40,95], 167 + while window and num_sum <= sum_list[window[-1]]: + window.pop() + while window and num_sum - sum_list[window[0]] >= k: + result = min(result, i - window.popleft()) + window.append(i) + return result if result < length + 1 else -1 +``` + ## 总结 - 熟悉栈的使用场景 @@ -594,3 +913,7 @@ class Solution: - [ ] [largest-rectangle-in-histogram](https://leetcode-cn.com/problems/largest-rectangle-in-histogram/) - [ ] [implement-queue-using-stacks](https://leetcode-cn.com/problems/implement-queue-using-stacks/) - [ ] [01-matrix](https://leetcode-cn.com/problems/01-matrix/) +- [ ] [largest-rectangle-in-histogram](https://leetcode-cn.com/problems/largest-rectangle-in-histogram/) +- [ ] [trapping-rain-water](https://leetcode-cn.com/problems/trapping-rain-water/) +- [ ] [sliding-window-maximum](https://leetcode-cn.com/problems/sliding-window-maximum/) +- [ ] [shortest-subarray-with-sum-at-least-k](https://leetcode-cn.com/problems/shortest-subarray-with-sum-at-least-k/) diff --git a/data_structure/union_find.md b/data_structure/union_find.md index c2340ec7..93147d03 100644 --- a/data_structure/union_find.md +++ b/data_structure/union_find.md @@ -35,6 +35,27 @@ class Solution: return edge ``` +```Python +class Solution: + def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: + parents = list(range(len(edges) + 1)) + + def find(index): + if parents[index] != index: + parents[index] = find(parents[index]) + return parents[index] + + def union(index1, index2): + parents[find(index1)] = find(index2) + + for node1, node2 in edges: + if find(node1) != find(node2): + union(node1, node2) + else: + return [node1, node2] + return [] +``` + ### [accounts-merge](https://leetcode-cn.com/problems/accounts-merge/) ```Python @@ -121,6 +142,24 @@ class Solution: return max_length ``` +```Python +class Solution: + def longestConsecutive(self, nums: List[int]) -> int: + nums_set = set(nums) + max_len = 0 + # start from the lowest + for num in nums_set: + if num -1 not in nums_set: + length = 1 + cur_num = num + while cur_num + 1 in nums_set: + length += 1 + cur_num += 1 + max_len = max(max_len, length) + return max_len + +``` + ### Kruskal's algorithm ### [minimum-risk-path](https://www.lintcode.com/problem/minimum-risk-path/description) @@ -163,4 +202,4 @@ class Solution: for w, x, y in edges: if union(x, y) and find(0) == find(N): # early return without constructing MST return w -``` \ No newline at end of file +``` diff --git a/introduction/python.md b/introduction/python.md index c139d1d4..71f185b9 100644 --- a/introduction/python.md +++ b/introduction/python.md @@ -32,6 +32,29 @@ b = tmp a, b = b, a ``` +#### 定义 + +```Python +ninf = float("-inf") +pinf = float("inf") +``` + +#### 翻转 +```Python +lst = [1, 2, 3, 4, 5] +reversed_lst = lst[::-1] +print(reversed_lst) # 输出:[5, 4, 3, 2, 1] + +lst = [1, 2, 3] +lst.reverse() +print(lst) # 输出: [3, 2, 1] + +lst = [1, 2, 3] +rev = reversed(lst) +print(list(rev)) # 输出: [3, 2, 1] +print(lst) # 原列表未变: [1, 2, 3] +``` + #### 连续不等式或等式 ```Python @@ -78,4 +101,4 @@ Python 的 [collections 库](https://docs.python.org/3/library/collections.html) ## 总结 -以上列举了一些用 Python3 做算法题时可以用到的一些特性,标准算法和数据结构,总结得肯定不全,因为 Python3 真的有很多可以利用的"骚操作",大家在学习本项目的时候也会见到,一下记不住也没关系,多实战就会了。 \ No newline at end of file +以上列举了一些用 Python3 做算法题时可以用到的一些特性,标准算法和数据结构,总结得肯定不全,因为 Python3 真的有很多可以利用的"骚操作",大家在学习本项目的时候也会见到,一下记不住也没关系,多实战就会了。 diff --git a/introduction/quickstart.md b/introduction/quickstart.md index 59a93e11..d9b91dd3 100644 --- a/introduction/quickstart.md +++ b/introduction/quickstart.md @@ -31,6 +31,17 @@ class Solution: - 循环时,i 不需要到 len-1 - 如果找到目标字符串,len(needle) == j +```Python +class Solution: + def strStr(self, haystack: str, needle: str) -> int: + len_needle = len(needle) + len_haystack = len(haystack) + for i in range(len_haystack-len_needle+1): + if haystack[i:i+len_needle] == needle: + return i + return -1 +``` + ### [示例 2:subsets](https://leetcode-cn.com/problems/subsets/) > 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 @@ -78,6 +89,24 @@ class Solution: 说明:后面会深入讲解几个典型的回溯算法问题,如果当前不太了解可以暂时先跳过 +```Python +class Solution: + def subsets(self, nums: List[int]) -> List[List[int]]: + if not nums: + return [] + result = [] + nums.sort() + def backtrack(lst, start): + result.append(lst) + for i in range(start, len(nums)): + number = nums[i] + if number not in lst: + backtrack(lst + [number], i) + backtrack([], 0) + return result +``` + + ## 面试注意点 我们大多数时候,刷算法题可能都是为了准备面试,所以面试的时候需要注意一些点