diff --git a/problems/0001.两数之和.md b/problems/0001.两数之和.md index 1af8787b..ca62e3ed 100644 --- a/problems/0001.两数之和.md +++ b/problems/0001.两数之和.md @@ -41,7 +41,7 @@ 那么我们就应该想到使用哈希法了。 -因为本地,我们不仅要知道元素有没有遍历过,还有知道这个元素对应的下标,**需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适**。 +因为本地,我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,**需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适**。 再来看一下使用数组和set来做哈希法的局限。 diff --git a/problems/0017.电话号码的字母组合.md b/problems/0017.电话号码的字母组合.md index d506bb88..cf5e4520 100644 --- a/problems/0017.电话号码的字母组合.md +++ b/problems/0017.电话号码的字母组合.md @@ -287,98 +287,153 @@ class Solution { ``` ## Python -**回溯** +回溯 ```python class Solution: def __init__(self): - self.answers: List[str] = [] - self.answer: str = '' - self.letter_map = { - '2': 'abc', - '3': 'def', - '4': 'ghi', - '5': 'jkl', - '6': 'mno', - '7': 'pqrs', - '8': 'tuv', - '9': 'wxyz' - } - - def letterCombinations(self, digits: str) -> List[str]: - self.answers.clear() - if not digits: return [] + self.letterMap = [ + "", # 0 + "", # 1 + "abc", # 2 + "def", # 3 + "ghi", # 4 + "jkl", # 5 + "mno", # 6 + "pqrs", # 7 + "tuv", # 8 + "wxyz" # 9 + ] + self.result = [] + self.s = "" + + def backtracking(self, digits, index): + if index == len(digits): + self.result.append(self.s) + return + digit = int(digits[index]) # 将索引处的数字转换为整数 + letters = self.letterMap[digit] # 获取对应的字符集 + for i in range(len(letters)): + self.s += letters[i] # 处理字符 + self.backtracking(digits, index + 1) # 递归调用,注意索引加1,处理下一个数字 + self.s = self.s[:-1] # 回溯,删除最后添加的字符 + + def letterCombinations(self, digits): + if len(digits) == 0: + return self.result self.backtracking(digits, 0) - return self.answers - - def backtracking(self, digits: str, index: int) -> None: - # 回溯函数没有返回值 - # Base Case - if index == len(digits): # 当遍历穷尽后的下一层时 - self.answers.append(self.answer) - return - # 单层递归逻辑 - letters: str = self.letter_map[digits[index]] - for letter in letters: - self.answer += letter # 处理 - self.backtracking(digits, index + 1) # 递归至下一层 - self.answer = self.answer[:-1] # 回溯 + return self.result + ``` -**回溯简化** +回溯精简(版本一) ```python class Solution: def __init__(self): - self.answers: List[str] = [] - self.letter_map = { - '2': 'abc', - '3': 'def', - '4': 'ghi', - '5': 'jkl', - '6': 'mno', - '7': 'pqrs', - '8': 'tuv', - '9': 'wxyz' - } - - def letterCombinations(self, digits: str) -> List[str]: - self.answers.clear() - if not digits: return [] - self.backtracking(digits, 0, '') - return self.answers + self.letterMap = [ + "", # 0 + "", # 1 + "abc", # 2 + "def", # 3 + "ghi", # 4 + "jkl", # 5 + "mno", # 6 + "pqrs", # 7 + "tuv", # 8 + "wxyz" # 9 + ] + self.result = [] - def backtracking(self, digits: str, index: int, answer: str) -> None: - # 回溯函数没有返回值 - # Base Case - if index == len(digits): # 当遍历穷尽后的下一层时 - self.answers.append(answer) - return - # 单层递归逻辑 - letters: str = self.letter_map[digits[index]] + def getCombinations(self, digits, index, s): + if index == len(digits): + self.result.append(s) + return + digit = int(digits[index]) + letters = self.letterMap[digit] for letter in letters: - self.backtracking(digits, index + 1, answer + letter) # 递归至下一层 + 回溯 + self.getCombinations(digits, index + 1, s + letter) + + def letterCombinations(self, digits): + if len(digits) == 0: + return self.result + self.getCombinations(digits, 0, "") + return self.result + ``` -**使用itertools** +回溯精简(版本二) ```python class Solution: - def letterCombinations(self, digits: str) -> List[str]: - import itertools - if not digits: - return list() - - phoneMap = { - "2": "abc", - "3": "def", - "4": "ghi", - "5": "jkl", - "6": "mno", - "7": "pqrs", - "8": "tuv", - "9": "wxyz", - } + def __init__(self): + self.letterMap = [ + "", # 0 + "", # 1 + "abc", # 2 + "def", # 3 + "ghi", # 4 + "jkl", # 5 + "mno", # 6 + "pqrs", # 7 + "tuv", # 8 + "wxyz" # 9 + ] + + def getCombinations(self, digits, index, s, result): + if index == len(digits): + result.append(s) + return + digit = int(digits[index]) + letters = self.letterMap[digit] + for letter in letters: + self.getCombinations(digits, index + 1, s + letter, result) + + def letterCombinations(self, digits): + result = [] + if len(digits) == 0: + return result + self.getCombinations(digits, 0, "", result) + return result + - groups = (phoneMap[digit] for digit in digits) - return ["".join(combination) for combination in itertools.product(*groups)] ``` +回溯优化使用列表 +```python +class Solution: + def __init__(self): + self.letterMap = [ + "", # 0 + "", # 1 + "abc", # 2 + "def", # 3 + "ghi", # 4 + "jkl", # 5 + "mno", # 6 + "pqrs", # 7 + "tuv", # 8 + "wxyz" # 9 + ] + + def getCombinations(self, digits, index, path, result): + if index == len(digits): + result.append(''.join(path)) + return + digit = int(digits[index]) + letters = self.letterMap[digit] + for letter in letters: + path.append(letter) + self.getCombinations(digits, index + 1, path, result) + path.pop() + + def letterCombinations(self, digits): + result = [] + if len(digits) == 0: + return result + self.getCombinations(digits, 0, [], result) + return result + + + +``` + + ## Go diff --git a/problems/0019.删除链表的倒数第N个节点.md b/problems/0019.删除链表的倒数第N个节点.md index c6f5bfc7..84eac96b 100644 --- a/problems/0019.删除链表的倒数第N个节点.md +++ b/problems/0019.删除链表的倒数第N个节点.md @@ -412,6 +412,28 @@ struct ListNode* removeNthFromEnd(struct ListNode* head, int n) { ``` +C#: +```csharp +public class Solution { + public ListNode RemoveNthFromEnd(ListNode head, int n) { + ListNode dummpHead = new ListNode(0); + dummpHead.next = head; + var fastNode = dummpHead; + var slowNode = dummpHead; + while(n-- != 0 && fastNode != null) + { + fastNode = fastNode.next; + } + while(fastNode.next != null) + { + fastNode = fastNode.next; + slowNode = slowNode.next; + } + slowNode.next = slowNode.next.next; + return dummpHead.next; + } +} +```
diff --git a/problems/0035.搜索插入位置.md b/problems/0035.搜索插入位置.md
index efc87577..04dd0cac 100644
--- a/problems/0035.搜索插入位置.md
+++ b/problems/0035.搜索插入位置.md
@@ -191,8 +191,8 @@ public:
};
```
-* 时间复杂度:$O(\log n)$
-* 时间复杂度:$O(1)$
+* 时间复杂度:O(log n)
+* 空间复杂度:O(1)
## 总结
diff --git a/problems/0039.组合总和.md b/problems/0039.组合总和.md
index e1e51923..4d9466c3 100644
--- a/problems/0039.组合总和.md
+++ b/problems/0039.组合总和.md
@@ -273,75 +273,101 @@ class Solution {
## Python
-**回溯**
+回溯(版本一)
```python
class Solution:
- def __init__(self):
- self.path = []
- self.paths = []
- def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
- '''
- 因为本题没有组合数量限制,所以只要元素总和大于target就算结束
- '''
- self.path.clear()
- self.paths.clear()
- self.backtracking(candidates, target, 0, 0)
- return self.paths
-
- def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
- # Base Case
- if sum_ == target:
- self.paths.append(self.path[:]) # 因为是shallow copy,所以不能直接传入self.path
+ def backtracking(self, candidates, target, total, startIndex, path, result):
+ if total > target:
return
- if sum_ > target:
+ if total == target:
+ result.append(path[:])
return
- # 单层递归逻辑
- for i in range(start_index, len(candidates)):
- sum_ += candidates[i]
- self.path.append(candidates[i])
- self.backtracking(candidates, target, sum_, i) # 因为无限制重复选取,所以不是i+1
- sum_ -= candidates[i] # 回溯
- self.path.pop() # 回溯
+ for i in range(startIndex, len(candidates)):
+ total += candidates[i]
+ path.append(candidates[i])
+ self.backtracking(candidates, target, total, i, path, result) # 不用i+1了,表示可以重复读取当前的数
+ total -= candidates[i]
+ path.pop()
+
+ def combinationSum(self, candidates, target):
+ result = []
+ self.backtracking(candidates, target, 0, 0, [], result)
+ return result
+
```
-**剪枝回溯**
+回溯剪枝(版本一)
```python
class Solution:
- def __init__(self):
- self.path = []
- self.paths = []
- def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
- '''
- 因为本题没有组合数量限制,所以只要元素总和大于target就算结束
- '''
- self.path.clear()
- self.paths.clear()
-
- # 为了剪枝需要提前进行排序
- candidates.sort()
- self.backtracking(candidates, target, 0, 0)
- return self.paths
-
- def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
- # Base Case
- if sum_ == target:
- self.paths.append(self.path[:]) # 因为是shallow copy,所以不能直接传入self.path
+ def backtracking(self, candidates, target, total, startIndex, path, result):
+ if total == target:
+ result.append(path[:])
return
- # 单层递归逻辑
- # 如果本层 sum + condidates[i] > target,就提前结束遍历,剪枝
- for i in range(start_index, len(candidates)):
- if sum_ + candidates[i] > target:
- return
- sum_ += candidates[i]
- self.path.append(candidates[i])
- self.backtracking(candidates, target, sum_, i) # 因为无限制重复选取,所以不是i-1
- sum_ -= candidates[i] # 回溯
- self.path.pop() # 回溯
+
+ for i in range(startIndex, len(candidates)):
+ if total + candidates[i] > target:
+ break
+ total += candidates[i]
+ path.append(candidates[i])
+ self.backtracking(candidates, target, total, i, path, result)
+ total -= candidates[i]
+ path.pop()
+
+ def combinationSum(self, candidates, target):
+ result = []
+ candidates.sort() # 需要排序
+ self.backtracking(candidates, target, 0, 0, [], result)
+ return result
+
+```
+
+回溯(版本二)
+
+```python
+class Solution:
+ def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
+ result =[]
+ self.backtracking(candidates, target, 0, [], result)
+ return result
+ def backtracking(self, candidates, target, startIndex, path, result):
+ if target == 0:
+ result.append(path[:])
+ return
+ if target < 0:
+ return
+ for i in range(startIndex, len(candidates)):
+ path.append(candidates[i])
+ self.backtracking(candidates, target - candidates[i], i, path, result)
+ path.pop()
+
+```
+
+回溯剪枝(版本二)
+
+```python
+class Solution:
+ def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
+ result =[]
+ candidates.sort()
+ self.backtracking(candidates, target, 0, [], result)
+ return result
+ def backtracking(self, candidates, target, startIndex, path, result):
+ if target == 0:
+ result.append(path[:])
+ return
+
+ for i in range(startIndex, len(candidates)):
+ if target - candidates[i] < 0:
+ break
+ path.append(candidates[i])
+ self.backtracking(candidates, target - candidates[i], i, path, result)
+ path.pop()
+
```
## Go
diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md
index b708650a..9094020e 100644
--- a/problems/0040.组合总和II.md
+++ b/problems/0040.组合总和II.md
@@ -356,93 +356,92 @@ class Solution {
```
## Python
-**回溯+巧妙去重(省去使用used**
+回溯
```python
class Solution:
- def __init__(self):
- self.paths = []
- self.path = []
- def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
- '''
- 类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
- '''
- self.paths.clear()
- self.path.clear()
- # 必须提前进行数组排序,避免重复
- candidates.sort()
- self.backtracking(candidates, target, 0, 0)
- return self.paths
- def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
- # Base Case
- if sum_ == target:
- self.paths.append(self.path[:])
+ def backtracking(self, candidates, target, total, startIndex, path, result):
+ if total == target:
+ result.append(path[:])
return
-
- # 单层递归逻辑
- for i in range(start_index, len(candidates)):
- # 剪枝,同39.组合总和
- if sum_ + candidates[i] > target:
- return
-
- # 跳过同一树层使用过的元素
- if i > start_index and candidates[i] == candidates[i-1]:
+
+ for i in range(startIndex, len(candidates)):
+ if i > startIndex and candidates[i] == candidates[i - 1]:
continue
-
- sum_ += candidates[i]
- self.path.append(candidates[i])
- self.backtracking(candidates, target, sum_, i+1)
- self.path.pop() # 回溯,为了下一轮for loop
- sum_ -= candidates[i] # 回溯,为了下一轮for loop
+
+ if total + candidates[i] > target:
+ break
+
+ total += candidates[i]
+ path.append(candidates[i])
+ self.backtracking(candidates, target, total, i + 1, path, result)
+ total -= candidates[i]
+ path.pop()
+
+ def combinationSum2(self, candidates, target):
+ result = []
+ candidates.sort()
+ self.backtracking(candidates, target, 0, 0, [], result)
+ return result
+
```
-**回溯+去重(使用used)**
+回溯 使用used
```python
class Solution:
- def __init__(self):
- self.paths = []
- self.path = []
- self.used = []
- def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
- '''
- 类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
- 本题需要使用used,用来标记区别同一树层的元素使用重复情况:注意区分递归纵向遍历遇到的重复元素,和for循环遇到的重复元素,这两者的区别
- '''
- self.paths.clear()
- self.path.clear()
- self.usage_list = [False] * len(candidates)
- # 必须提前进行数组排序,避免重复
- candidates.sort()
- self.backtracking(candidates, target, 0, 0)
- return self.paths
- def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
- # Base Case
- if sum_ == target:
- self.paths.append(self.path[:])
+ def backtracking(self, candidates, target, total, startIndex, used, path, result):
+ if total == target:
+ result.append(path[:])
return
-
- # 单层递归逻辑
- for i in range(start_index, len(candidates)):
- # 剪枝,同39.组合总和
- if sum_ + candidates[i] > target:
- return
-
- # 检查同一树层是否出现曾经使用过的相同元素
- # 若数组中前后元素值相同,但前者却未被使用(used == False),说明是for loop中的同一树层的相同元素情况
- if i > 0 and candidates[i] == candidates[i-1] and self.usage_list[i-1] == False:
+
+ for i in range(startIndex, len(candidates)):
+ # 对于相同的数字,只选择第一个未被使用的数字,跳过其他相同数字
+ if i > startIndex and candidates[i] == candidates[i - 1] and not used[i - 1]:
continue
- sum_ += candidates[i]
- self.path.append(candidates[i])
- self.usage_list[i] = True
- self.backtracking(candidates, target, sum_, i+1)
- self.usage_list[i] = False # 回溯,为了下一轮for loop
- self.path.pop() # 回溯,为了下一轮for loop
- sum_ -= candidates[i] # 回溯,为了下一轮for loop
-```
+ if total + candidates[i] > target:
+ break
+ total += candidates[i]
+ path.append(candidates[i])
+ used[i] = True
+ self.backtracking(candidates, target, total, i + 1, used, path, result)
+ used[i] = False
+ total -= candidates[i]
+ path.pop()
+
+ def combinationSum2(self, candidates, target):
+ used = [False] * len(candidates)
+ result = []
+ candidates.sort()
+ self.backtracking(candidates, target, 0, 0, used, [], result)
+ return result
+
+```
+回溯优化
+```python
+class Solution:
+ def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
+ candidates.sort()
+ results = []
+ self.combinationSumHelper(candidates, target, 0, [], results)
+ return results
+
+ def combinationSumHelper(self, candidates, target, index, path, results):
+ if target == 0:
+ results.append(path[:])
+ return
+ for i in range(index, len(candidates)):
+ if i > index and candidates[i] == candidates[i - 1]:
+ continue
+ if candidates[i] > target:
+ break
+ path.append(candidates[i])
+ self.combinationSumHelper(candidates, target - candidates[i], i + 1, path, results)
+ path.pop()
+```
## Go
主要在于如何在回溯中去重
diff --git a/problems/0045.跳跃游戏II.md b/problems/0045.跳跃游戏II.md
index 8a939582..2f0349b2 100644
--- a/problems/0045.跳跃游戏II.md
+++ b/problems/0045.跳跃游戏II.md
@@ -205,66 +205,81 @@ class Solution {
```
### Python
-
+贪心(版本一)
```python
class Solution:
- def jump(self, nums: List[int]) -> int:
- if len(nums) == 1: return 0
- ans = 0
- curDistance = 0
- nextDistance = 0
- for i in range(len(nums)):
- nextDistance = max(i + nums[i], nextDistance)
- if i == curDistance:
- if curDistance != len(nums) - 1:
- ans += 1
- curDistance = nextDistance
- if nextDistance >= len(nums) - 1: break
- return ans
-```
-
-```python
-# 贪心版本二
-class Solution:
- def jump(self, nums: List[int]) -> int:
+ def jump(self, nums):
if len(nums) == 1:
return 0
- curDistance, nextDistance = 0, 0
- step = 0
- for i in range(len(nums)-1):
- nextDistance = max(nextDistance, nums[i]+i)
- if i == curDistance:
- curDistance = nextDistance
- step += 1
- return step
-```
-```python
-# 贪心版本三 - 类似‘55-跳跃游戏’写法
-class Solution:
- def jump(self, nums) -> int:
- if len(nums)==1: return 0
- i = 0
- count = 0
- cover = 0
- while i<=cover:
- for i in range(i,cover+1):
- cover = max(nums[i]+i,cover)
- if cover>=len(nums)-1: return count+1
- count+=1
+ cur_distance = 0 # 当前覆盖最远距离下标
+ ans = 0 # 记录走的最大步数
+ next_distance = 0 # 下一步覆盖最远距离下标
+
+ for i in range(len(nums)):
+ next_distance = max(nums[i] + i, next_distance) # 更新下一步覆盖最远距离下标
+ if i == cur_distance: # 遇到当前覆盖最远距离下标
+ ans += 1 # 需要走下一步
+ cur_distance = next_distance # 更新当前覆盖最远距离下标(相当于加油了)
+ if next_distance >= len(nums) - 1: # 当前覆盖最远距离达到数组末尾,不用再做ans++操作,直接结束
+ break
+
+ return ans
+
```
+贪心(版本二)
```python
-# 动态规划做法
+class Solution:
+ def jump(self, nums):
+ cur_distance = 0 # 当前覆盖的最远距离下标
+ ans = 0 # 记录走的最大步数
+ next_distance = 0 # 下一步覆盖的最远距离下标
+
+ for i in range(len(nums) - 1): # 注意这里是小于len(nums) - 1,这是关键所在
+ next_distance = max(nums[i] + i, next_distance) # 更新下一步覆盖的最远距离下标
+ if i == cur_distance: # 遇到当前覆盖的最远距离下标
+ cur_distance = next_distance # 更新当前覆盖的最远距离下标
+ ans += 1
+
+ return ans
+
+```
+贪心(版本三) 类似‘55-跳跃游戏’写法
+
+```python
+class Solution:
+ def jump(self, nums) -> int:
+ if len(nums)==1: # 如果数组只有一个元素,不需要跳跃,步数为0
+ return 0
+
+ i = 0 # 当前位置
+ count = 0 # 步数计数器
+ cover = 0 # 当前能够覆盖的最远距离
+
+ while i <= cover: # 当前位置小于等于当前能够覆盖的最远距离时循环
+ for i in range(i, cover+1): # 遍历从当前位置到当前能够覆盖的最远距离之间的所有位置
+ cover = max(nums[i]+i, cover) # 更新当前能够覆盖的最远距离
+ if cover >= len(nums)-1: # 如果当前能够覆盖的最远距离达到或超过数组的最后一个位置,直接返回步数+1
+ return count+1
+ count += 1 # 每一轮遍历结束后,步数+1
+
+
+```
+动态规划
+```python
class Solution:
def jump(self, nums: List[int]) -> int:
- result = [10**4+1]*len(nums)
- result[0]=0
- for i in range(len(nums)):
- for j in range(nums[i]+1):
- if i+j
diff --git a/problems/0198.打家劫舍.md b/problems/0198.打家劫舍.md
index 6e682ec3..bed7a4ea 100644
--- a/problems/0198.打家劫舍.md
+++ b/problems/0198.打家劫舍.md
@@ -141,7 +141,36 @@ class Solution {
}
}
-// 空间优化 dp数组只存与计算相关的两次数据
+// 使用滚动数组思想,优化空间
+// 分析本题可以发现,所求结果仅依赖于前两种状态,此时可以使用滚动数组思想将空间复杂度降低为3个空间
+class Solution {
+ public int rob(int[] nums) {
+
+ int len = nums.length;
+
+ if (len == 0) return 0;
+ else if (len == 1) return nums[0];
+ else if (len == 2) return Math.max(nums[0],nums[1]);
+
+
+ int[] result = new int[3]; //存放选择的结果
+ result[0] = nums[0];
+ result[1] = Math.max(nums[0],nums[1]);
+
+
+ for(int i=2;i
diff --git a/problems/0213.打家劫舍II.md b/problems/0213.打家劫舍II.md
index 6395f3a8..3f532a41 100644
--- a/problems/0213.打家劫舍II.md
+++ b/problems/0213.打家劫舍II.md
@@ -130,40 +130,93 @@ class Solution {
```
Python:
+
```Python
class Solution:
def rob(self, nums: List[int]) -> int:
- #在198入门级的打家劫舍问题上分两种情况考虑
- #一是不偷第一间房,二是不偷最后一间房
- if len(nums)==1:#题目中提示nums.length>=1,所以不需要考虑len(nums)==0的情况
+ if len(nums) == 0:
+ return 0
+ if len(nums) == 1:
return nums[0]
- val1=self.roblist(nums[1:])#不偷第一间房
- val2=self.roblist(nums[:-1])#不偷最后一间房
- return max(val1,val2)
+
+ result1 = self.robRange(nums, 0, len(nums) - 2) # 情况二
+ result2 = self.robRange(nums, 1, len(nums) - 1) # 情况三
+ return max(result1, result2)
+ # 198.打家劫舍的逻辑
+ def robRange(self, nums: List[int], start: int, end: int) -> int:
+ if end == start:
+ return nums[start]
+
+ prev_max = nums[start]
+ curr_max = max(nums[start], nums[start + 1])
+
+ for i in range(start + 2, end + 1):
+ temp = curr_max
+ curr_max = max(prev_max + nums[i], curr_max)
+ prev_max = temp
+
+ return curr_max
- def roblist(self,nums):
- l=len(nums)
- dp=[0]*l
- dp[0]=nums[0]
- for i in range(1,l):
- if i==1:
- dp[i]=max(dp[i-1],nums[i])
- else:
- dp[i]=max(dp[i-1],dp[i-2]+nums[i])
- return dp[-1]
```
+2维DP
```python
-class Solution: # 二维dp数组写法
+class Solution:
def rob(self, nums: List[int]) -> int:
- if len(nums)<3: return max(nums)
- return max(self.default(nums[:-1]),self.default(nums[1:]))
- def default(self,nums):
- dp = [[0,0] for _ in range(len(nums))]
+ if len(nums) < 3:
+ return max(nums)
+
+ # 情况二:不抢劫第一个房屋
+ result1 = self.robRange(nums[:-1])
+
+ # 情况三:不抢劫最后一个房屋
+ result2 = self.robRange(nums[1:])
+
+ return max(result1, result2)
+
+ def robRange(self, nums):
+ dp = [[0, 0] for _ in range(len(nums))]
dp[0][1] = nums[0]
- for i in range(1,len(nums)):
- dp[i][0] = max(dp[i-1])
- dp[i][1] = dp[i-1][0] + nums[i]
+
+ for i in range(1, len(nums)):
+ dp[i][0] = max(dp[i - 1])
+ dp[i][1] = dp[i - 1][0] + nums[i]
+
return max(dp[-1])
+
+
+
+```
+
+优化版
+```python
+class Solution:
+ def rob(self, nums: List[int]) -> int:
+ if not nums: # 如果没有房屋,返回0
+ return 0
+
+ if len(nums) == 1: # 如果只有一个房屋,返回该房屋的金额
+ return nums[0]
+
+ # 情况二:不抢劫第一个房屋
+ prev_max = 0 # 上一个房屋的最大金额
+ curr_max = 0 # 当前房屋的最大金额
+ for num in nums[1:]:
+ temp = curr_max # 临时变量保存当前房屋的最大金额
+ curr_max = max(prev_max + num, curr_max) # 更新当前房屋的最大金额
+ prev_max = temp # 更新上一个房屋的最大金额
+ result1 = curr_max
+
+ # 情况三:不抢劫最后一个房屋
+ prev_max = 0 # 上一个房屋的最大金额
+ curr_max = 0 # 当前房屋的最大金额
+ for num in nums[:-1]:
+ temp = curr_max # 临时变量保存当前房屋的最大金额
+ curr_max = max(prev_max + num, curr_max) # 更新当前房屋的最大金额
+ prev_max = temp # 更新上一个房屋的最大金额
+ result2 = curr_max
+
+ return max(result1, result2)
+
```
Go:
diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md
index f08d77ea..319b2eba 100644
--- a/problems/0216.组合总和III.md
+++ b/problems/0216.组合总和III.md
@@ -362,28 +362,25 @@ class Solution {
```py
class Solution:
- def __init__(self):
- self.res = []
- self.sum_now = 0
- self.path = []
+ def combinationSum3(self, k: int, n: int) -> List[List[int]]:
+ result = [] # 存放结果集
+ self.backtracking(n, k, 0, 1, [], result)
+ return result
- def combinationSum3(self, k: int, n: int) -> [[int]]:
- self.backtracking(k, n, 1)
- return self.res
+ def backtracking(self, targetSum, k, currentSum, startIndex, path, result):
+ if currentSum > targetSum: # 剪枝操作
+ return # 如果path的长度等于k但currentSum不等于targetSum,则直接返回
+ if len(path) == k:
+ if currentSum == targetSum:
+ result.append(path[:])
+ return
+ for i in range(startIndex, 9 - (k - len(path)) + 2): # 剪枝
+ currentSum += i # 处理
+ path.append(i) # 处理
+ self.backtracking(targetSum, k, currentSum, i + 1, path, result) # 注意i+1调整startIndex
+ currentSum -= i # 回溯
+ path.pop() # 回溯
- def backtracking(self, k: int, n: int, start_num: int):
- if self.sum_now > n: # 剪枝
- return
- if len(self.path) == k: # len(path)==k时不管sum是否等于n都会返回
- if self.sum_now == n:
- self.res.append(self.path[:])
- return
- for i in range(start_num, 10 - (k - len(self.path)) + 1):
- self.path.append(i)
- self.sum_now += i
- self.backtracking(k, n, i + 1)
- self.path.pop()
- self.sum_now -= i
```
## Go
diff --git a/problems/0225.用队列实现栈.md b/problems/0225.用队列实现栈.md
index 41a1ede2..94c79404 100644
--- a/problems/0225.用队列实现栈.md
+++ b/problems/0225.用队列实现栈.md
@@ -367,7 +367,7 @@ class MyStack {
```
优化,使用一个 Queue 实现,但用卡哥的逻辑实现
-```
+```Java
class MyStack {
Queue
diff --git a/problems/0235.二叉搜索树的最近公共祖先.md b/problems/0235.二叉搜索树的最近公共祖先.md
index 8353303a..9777bb0b 100644
--- a/problems/0235.二叉搜索树的最近公共祖先.md
+++ b/problems/0235.二叉搜索树的最近公共祖先.md
@@ -275,34 +275,57 @@ class Solution {
## Python
-递归法:
+递归法(版本一)
```python
class Solution:
- """二叉搜索树的最近公共祖先 递归法"""
+ def traversal(self, cur, p, q):
+ if cur is None:
+ return cur
+ # 中
+ if cur.val > p.val and cur.val > q.val: # 左
+ left = self.traversal(cur.left, p, q)
+ if left is not None:
+ return left
- def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
- if root.val > p.val and root.val > q.val:
- return self.lowestCommonAncestor(root.left, p, q)
- if root.val < p.val and root.val < q.val:
- return self.lowestCommonAncestor(root.right, p, q)
- return root
+ if cur.val < p.val and cur.val < q.val: # 右
+ right = self.traversal(cur.right, p, q)
+ if right is not None:
+ return right
+
+ return cur
+
+ def lowestCommonAncestor(self, root, p, q):
+ return self.traversal(root, p, q)
```
-迭代法:
+迭代法(版本二)精简
```python
class Solution:
- """二叉搜索树的最近公共祖先 迭代法"""
+ def lowestCommonAncestor(self, root, p, q):
+ if root.val > p.val and root.val > q.val:
+ return self.lowestCommonAncestor(root.left, p, q)
+ elif root.val < p.val and root.val < q.val:
+ return self.lowestCommonAncestor(root.right, p, q)
+ else:
+ return root
- def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
- while True:
+```
+
+迭代法
+```python
+class Solution:
+ def lowestCommonAncestor(self, root, p, q):
+ while root:
if root.val > p.val and root.val > q.val:
root = root.left
elif root.val < p.val and root.val < q.val:
root = root.right
else:
return root
-```
+ return None
+
+```
## Go
递归法:
diff --git a/problems/0236.二叉树的最近公共祖先.md b/problems/0236.二叉树的最近公共祖先.md
index 33201def..0ebd5566 100644
--- a/problems/0236.二叉树的最近公共祖先.md
+++ b/problems/0236.二叉树的最近公共祖先.md
@@ -274,25 +274,44 @@ class Solution {
```
## Python
-
+递归法(版本一)
```python
class Solution:
- """二叉树的最近公共祖先 递归法"""
-
- def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
- if not root or root == p or root == q:
+ def lowestCommonAncestor(self, root, p, q):
+ if root == q or root == p or root is None:
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
- return right
-```
+ if left is not None and right is not None:
+ return root
+
+ if left is None and right is not None:
+ return right
+ elif left is not None and right is None:
+ return left
+ else:
+ return None
+```
+递归法(版本二)精简
+```python
+class Solution:
+ def lowestCommonAncestor(self, root, p, q):
+ if root == q or root == p or root is None:
+ return root
+
+ left = self.lowestCommonAncestor(root.left, p, q)
+ right = self.lowestCommonAncestor(root.right, p, q)
+
+ if left is not None and right is not None:
+ return root
+
+ if left is None:
+ return right
+ return left
+
+```
## Go
```Go
diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md
index c396f4a0..7bd56fbd 100644
--- a/problems/0257.二叉树的所有路径.md
+++ b/problems/0257.二叉树的所有路径.md
@@ -470,38 +470,34 @@ class Solution {
## Python:
-递归法+回溯(版本一)
+递归法+回溯
```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
-import copy
-from typing import List, Optional
-
class Solution:
- def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
- if not root:
- return []
+ def traversal(self, cur, path, result):
+ path.append(cur.val) # 中
+ if not cur.left and not cur.right: # 到达叶子节点
+ sPath = '->'.join(map(str, path))
+ result.append(sPath)
+ return
+ if cur.left: # 左
+ self.traversal(cur.left, path, result)
+ path.pop() # 回溯
+ if cur.right: # 右
+ self.traversal(cur.right, path, result)
+ path.pop() # 回溯
+
+ def binaryTreePaths(self, root):
result = []
- self.generate_paths(root, [], result)
+ path = []
+ if not root:
+ return result
+ self.traversal(root, path, result)
return result
-
- def generate_paths(self, node: TreeNode, path: List[int], result: List[str]) -> None:
- path.append(node.val)
- if not node.left and not node.right:
- result.append('->'.join(map(str, path)))
- if node.left:
- self.generate_paths(node.left, copy.copy(path), result)
- if node.right:
- self.generate_paths(node.right, copy.copy(path), result)
- path.pop()
```
-递归法+回溯(版本二)
+递归法+隐形回溯(版本一)
```Python
# Definition for a binary tree node.
# class TreeNode:
@@ -509,7 +505,6 @@ class Solution:
# self.val = val
# self.left = left
# self.right = right
-import copy
from typing import List, Optional
class Solution:
@@ -517,23 +512,23 @@ class Solution:
if not root:
return []
result = []
- self.generate_paths(root, [], result)
+ self.traversal(root, [], result)
return result
- def generate_paths(self, node: TreeNode, path: List[int], result: List[str]) -> None:
- if not node:
+ def traversal(self, cur: TreeNode, path: List[int], result: List[str]) -> None:
+ if not cur:
return
- path.append(node.val)
- if not node.left and not node.right:
+ path.append(cur.val)
+ if not cur.left and not cur.right:
result.append('->'.join(map(str, path)))
- else:
- self.generate_paths(node.left, copy.copy(path), result)
- self.generate_paths(node.right, copy.copy(path), result)
- path.pop()
+ if cur.left:
+ self.traversal(cur.left, path[:], result)
+ if cur.right:
+ self.traversal(cur.right, path[:], result)
```
-递归法+隐形回溯
+递归法+隐形回溯(版本二)
```Python
# Definition for a binary tree node.
# class TreeNode:
@@ -566,16 +561,11 @@ class Solution:
迭代法:
```Python
-from collections import deque
-
-
class Solution:
- """二叉树的所有路径 迭代法"""
def binaryTreePaths(self, root: TreeNode) -> List[str]:
# 题目中节点数至少为1
- stack, path_st, result = deque([root]), deque(), []
- path_st.append(str(root.val))
+ stack, path_st, result = [root], [str(root.val)], []
while stack:
cur = stack.pop()
diff --git a/problems/0279.完全平方数.md b/problems/0279.完全平方数.md
index f5b23d26..80b69f0c 100644
--- a/problems/0279.完全平方数.md
+++ b/problems/0279.完全平方数.md
@@ -217,36 +217,61 @@ class Solution {
Python:
+先遍历物品, 再遍历背包
```python
class Solution:
def numSquares(self, n: int) -> int:
- '''版本一,先遍历背包, 再遍历物品'''
- # 初始化
- nums = [i**2 for i in range(1, n + 1) if i**2 <= n]
- dp = [10**4]*(n + 1)
+ dp = [float('inf')] * (n + 1)
dp[0] = 0
- # 遍历背包
- for j in range(1, n + 1):
- # 遍历物品
- for num in nums:
- if j >= num:
- dp[j] = min(dp[j], dp[j - num] + 1)
- return dp[n]
-
- def numSquares1(self, n: int) -> int:
- '''版本二, 先遍历物品, 再遍历背包'''
- # 初始化
- nums = [i**2 for i in range(1, n + 1) if i**2 <= n]
- dp = [10**4]*(n + 1)
- dp[0] = 0
- # 遍历物品
- for num in nums:
- # 遍历背包
- for j in range(num, n + 1):
- dp[j] = min(dp[j], dp[j - num] + 1)
- return dp[n]
-```
+ for i in range(1, n + 1): # 遍历背包
+ for j in range(1, int(i ** 0.5) + 1): # 遍历物品
+ # 更新凑成数字 i 所需的最少完全平方数数量
+ dp[i] = min(dp[i], dp[i - j * j] + 1)
+
+ return dp[n]
+
+```
+先遍历背包, 再遍历物品
+```python
+class Solution:
+ def numSquares(self, n: int) -> int:
+ dp = [float('inf')] * (n + 1)
+ dp[0] = 0
+
+ for i in range(1, int(n ** 0.5) + 1): # 遍历物品
+ for j in range(i * i, n + 1): # 遍历背包
+ # 更新凑成数字 j 所需的最少完全平方数数量
+ dp[j] = min(dp[j - i * i] + 1, dp[j])
+
+ return dp[n]
+
+
+```
+其他版本
+```python
+class Solution:
+ def numSquares(self, n: int) -> int:
+ # 创建动态规划数组,初始值为最大值
+ dp = [float('inf')] * (n + 1)
+ # 初始化已知情况
+ dp[0] = 0
+
+ # 遍历背包容量
+ for i in range(1, n + 1):
+ # 遍历完全平方数作为物品
+ j = 1
+ while j * j <= i:
+ # 更新最少完全平方数的数量
+ dp[i] = min(dp[i], dp[i - j * j] + 1)
+ j += 1
+
+ # 返回结果
+ return dp[n]
+
+
+
+```
Go:
```go
// 版本一,先遍历物品, 再遍历背包
diff --git a/problems/0300.最长上升子序列.md b/problems/0300.最长上升子序列.md
index e1f2bef8..b46cafc0 100644
--- a/problems/0300.最长上升子序列.md
+++ b/problems/0300.最长上升子序列.md
@@ -154,7 +154,7 @@ class Solution:
if len(nums) <= 1:
return len(nums)
dp = [1] * len(nums)
- result = 0
+ result = 1
for i in range(1, len(nums)):
for j in range(0, i):
if nums[i] > nums[j]:
diff --git a/problems/0322.零钱兑换.md b/problems/0322.零钱兑换.md
index 0e3947da..67b1a6d9 100644
--- a/problems/0322.零钱兑换.md
+++ b/problems/0322.零钱兑换.md
@@ -217,36 +217,76 @@ class Solution {
Python:
+
+先遍历物品 后遍历背包
```python
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
- '''版本一'''
- # 初始化
- dp = [float("inf")]*(amount + 1)
- dp[0] = 0
- # 遍历物品
- for coin in coins:
- # 遍历背包
- for j in range(coin, amount + 1):
- dp[j] = min(dp[j], dp[j - coin] + 1)
- return dp[amount] if dp[amount] != float("inf") else -1
+ dp = [float('inf')] * (amount + 1) # 创建动态规划数组,初始值为正无穷大
+ dp[0] = 0 # 初始化背包容量为0时的最小硬币数量为0
+
+ for coin in coins: # 遍历硬币列表,相当于遍历物品
+ for i in range(coin, amount + 1): # 遍历背包容量
+ if dp[i - coin] != float('inf'): # 如果dp[i - coin]不是初始值,则进行状态转移
+ dp[i] = min(dp[i - coin] + 1, dp[i]) # 更新最小硬币数量
+
+ if dp[amount] == float('inf'): # 如果最终背包容量的最小硬币数量仍为正无穷大,表示无解
+ return -1
+ return dp[amount] # 返回背包容量为amount时的最小硬币数量
- def coinChange1(self, coins: List[int], amount: int) -> int:
- '''版本二'''
- # 初始化
- dp = [float("inf")]*(amount + 1)
- dp[0] = 0
- # 遍历物品
- for j in range(1, amount + 1):
- # 遍历背包
- for coin in coins:
- if j >= coin:
- dp[j] = min(dp[j], dp[j - coin] + 1)
- return dp[amount] if dp[amount] != float("inf") else -1
```
+先遍历背包 后遍历物品
+```python
+class Solution:
+ def coinChange(self, coins: List[int], amount: int) -> int:
+ dp = [float('inf')] * (amount + 1) # 创建动态规划数组,初始值为正无穷大
+ dp[0] = 0 # 初始化背包容量为0时的最小硬币数量为0
+
+ for i in range(1, amount + 1): # 遍历背包容量
+ for j in range(len(coins)): # 遍历硬币列表,相当于遍历物品
+ if i - coins[j] >= 0 and dp[i - coins[j]] != float('inf'): # 如果dp[i - coins[j]]不是初始值,则进行状态转移
+ dp[i] = min(dp[i - coins[j]] + 1, dp[i]) # 更新最小硬币数量
+
+ if dp[amount] == float('inf'): # 如果最终背包容量的最小硬币数量仍为正无穷大,表示无解
+ return -1
+ return dp[amount] # 返回背包容量为amount时的最小硬币数量
+
+```
+先遍历物品 后遍历背包(优化版)
+```python
+class Solution:
+ def coinChange(self, coins: List[int], amount: int) -> int:
+ dp = [float('inf')] * (amount + 1)
+ dp[0] = 0
+
+ for coin in coins:
+ for i in range(coin, amount + 1): # 进行优化,从能装得下的背包开始计算,则不需要进行比较
+ # 更新凑成金额 i 所需的最少硬币数量
+ dp[i] = min(dp[i], dp[i - coin] + 1)
+
+ return dp[amount] if dp[amount] != float('inf') else -1
+```
+先遍历背包 后遍历物品(优化版)
+```python
+class Solution:
+ def coinChange(self, coins: List[int], amount: int) -> int:
+ dp = [float('inf')] * (amount + 1)
+ dp[0] = 0
+
+ for i in range(1, amount + 1): # 遍历背包容量
+ for coin in coins: # 遍历物品
+ if i - coin >= 0:
+ # 更新凑成金额 i 所需的最少硬币数量
+ dp[i] = min(dp[i], dp[i - coin] + 1)
+
+ return dp[amount] if dp[amount] != float('inf') else -1
+
+
+
+```
Go:
```go
diff --git a/problems/0332.重新安排行程.md b/problems/0332.重新安排行程.md
index 95e7d3ed..fa6414e9 100644
--- a/problems/0332.重新安排行程.md
+++ b/problems/0332.重新安排行程.md
@@ -347,64 +347,88 @@ class Solution {
```
### python
+回溯 使用used数组
```python
class Solution:
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
- # defaultdic(list) 是为了方便直接append
- tickets_dict = defaultdict(list)
- for item in tickets:
- tickets_dict[item[0]].append(item[1])
- # 给每一个机场的到达机场排序,小的在前面,在回溯里首先被pop(0)出去
- # 这样最先找的的path就是排序最小的答案,直接返回
- for airport in tickets_dict: tickets_dict[airport].sort()
- '''
- tickets_dict里面的内容是这样的
- {'JFK': ['ATL', 'SFO'], 'SFO': ['ATL'], 'ATL': ['JFK', 'SFO']})
- '''
- path = ["JFK"]
- def backtracking(start_point):
- # 终止条件
- if len(path) == len(tickets) + 1:
- return True
- for _ in tickets_dict[start_point]:
- #必须及时删除,避免出现死循环
- end_point = tickets_dict[start_point].pop(0)
- path.append(end_point)
- # 只要找到一个就可以返回了
- if backtracking(end_point):
- return True
- path.pop()
- tickets_dict[start_point].append(end_point)
-
- backtracking("JFK")
- return path
-```
-
-python - 使用used数组 - 神似之前几题写法
-
-```python
-class Solution:
- def findItinerary(self, tickets: List[List[str]]) -> List[str]:
- global used,path,results
- used = [0]*len(tickets)
+ tickets.sort() # 先排序,这样一旦找到第一个可行路径,一定是字母排序最小的
+ used = [0] * len(tickets)
path = ['JFK']
results = []
- tickets.sort() # 先排序,这样一旦找到第一个可行路径,一定是字母排序最小的
- self.backtracking(tickets,'JFK')
+ self.backtracking(tickets, used, path, 'JFK', results)
return results[0]
- def backtracking(self,tickets,cur):
- if sum(used) == len(tickets):
- results.append(path[:])
- return True # 只要找到就返回
- for i in range(len(tickets)):
- if tickets[i][0]==cur and used[i]==0:
- used[i]=1
- path.append(tickets[i][1])
- state = self.backtracking(tickets,tickets[i][1])
- path.pop()
- used[i]=0
- if state: return True # 只要找到就返回,不继续搜索了
+
+ def backtracking(self, tickets, used, path, cur, results):
+ if len(path) == len(tickets) + 1: # 终止条件:路径长度等于机票数量+1
+ results.append(path[:]) # 将当前路径添加到结果列表
+ return True
+
+ for i, ticket in enumerate(tickets): # 遍历机票列表
+ if ticket[0] == cur and used[i] == 0: # 找到起始机场为cur且未使用过的机票
+ used[i] = 1 # 标记该机票为已使用
+ path.append(ticket[1]) # 将到达机场添加到路径中
+ state = self.backtracking(tickets, used, path, ticket[1], results) # 递归搜索
+ path.pop() # 回溯,移除最后添加的到达机场
+ used[i] = 0 # 标记该机票为未使用
+ if state:
+ return True # 只要找到一个可行路径就返回,不继续搜索
+
+```
+回溯 使用字典
+```python
+from collections import defaultdict
+
+class Solution:
+ def findItinerary(self, tickets: List[List[str]]) -> List[str]:
+ targets = defaultdict(list) # 构建机场字典
+ for ticket in tickets:
+ targets[ticket[0]].append(ticket[1])
+ for airport in targets:
+ targets[airport].sort() # 对目的地列表进行排序
+
+ path = ["JFK"] # 起始机场为"JFK"
+ self.backtracking(targets, path, len(tickets))
+ return path
+
+ def backtracking(self, targets, path, ticketNum):
+ if len(path) == ticketNum + 1:
+ return True # 找到有效行程
+
+ airport = path[-1] # 当前机场
+ destinations = targets[airport] # 当前机场可以到达的目的地列表
+ for i, dest in enumerate(destinations):
+ targets[airport].pop(i) # 标记已使用的机票
+ path.append(dest) # 添加目的地到路径
+ if self.backtracking(targets, path, ticketNum):
+ return True # 找到有效行程
+ targets[airport].insert(i, dest) # 回溯,恢复机票
+ path.pop() # 移除目的地
+ return False # 没有找到有效行程
+
+```
+回溯 使用字典 逆序
+```python
+from collections import defaultdict
+
+class Solution:
+ def findItinerary(self, tickets):
+ targets = defaultdict(list) # 创建默认字典,用于存储机场映射关系
+ for ticket in tickets:
+ targets[ticket[0]].append(ticket[1]) # 将机票输入到字典中
+
+ for key in targets:
+ targets[key].sort(reverse=True) # 对到达机场列表进行字母逆序排序
+
+ result = []
+ self.backtracking("JFK", targets, result) # 调用回溯函数开始搜索路径
+ return result[::-1] # 返回逆序的行程路径
+
+ def backtracking(self, airport, targets, result):
+ while targets[airport]: # 当机场还有可到达的机场时
+ next_airport = targets[airport].pop() # 弹出下一个机场
+ self.backtracking(next_airport, targets, result) # 递归调用回溯函数进行深度优先搜索
+ result.append(airport) # 将当前机场添加到行程路径中
```
### GO
diff --git a/problems/0343.整数拆分.md b/problems/0343.整数拆分.md
index ddd6f162..d70641db 100644
--- a/problems/0343.整数拆分.md
+++ b/problems/0343.整数拆分.md
@@ -245,20 +245,68 @@ class Solution {
```
### Python
+动态规划(版本一)
```python
class Solution:
- def integerBreak(self, n: int) -> int:
- dp = [0] * (n + 1)
- dp[2] = 1
+ # 假设对正整数 i 拆分出的第一个正整数是 j(1 <= j < i),则有以下两种方案:
+ # 1) 将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j * (i-j)
+ # 2) 将 i 拆分成 j 和 i−j 的和,且 i−j 继续拆分成多个正整数,此时的乘积是 j * dp[i-j]
+ def integerBreak(self, n):
+ dp = [0] * (n + 1) # 创建一个大小为n+1的数组来存储计算结果
+ dp[2] = 1 # 初始化dp[2]为1,因为当n=2时,只有一个切割方式1+1=2,乘积为1
+
+ # 从3开始计算,直到n
for i in range(3, n + 1):
- # 假设对正整数 i 拆分出的第一个正整数是 j(1 <= j < i),则有以下两种方案:
- # 1) 将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j * (i-j)
- # 2) 将 i 拆分成 j 和 i−j 的和,且 i−j 继续拆分成多个正整数,此时的乘积是 j * dp[i-j]
+ # 遍历所有可能的切割点
for j in range(1, i // 2 + 1):
- dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
- return dp[n]
-```
+ # 计算切割点j和剩余部分(i-j)的乘积,并与之前的结果进行比较取较大值
+
+ dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j))
+
+ return dp[n] # 返回最终的计算结果
+
+```
+动态规划(版本二)
+```python
+class Solution:
+ def integerBreak(self, n):
+ if n <= 3:
+ return 1 * (n - 1) # 对于n小于等于3的情况,返回1 * (n - 1)
+
+ dp = [0] * (n + 1) # 创建一个大小为n+1的数组来存储最大乘积结果
+ dp[1] = 1 # 当n等于1时,最大乘积为1
+ dp[2] = 2 # 当n等于2时,最大乘积为2
+ dp[3] = 3 # 当n等于3时,最大乘积为3
+
+ # 从4开始计算,直到n
+ for i in range(4, n + 1):
+ # 遍历所有可能的切割点
+ for j in range(1, i // 2 + 1):
+ # 计算切割点j和剩余部分(i - j)的乘积,并与之前的结果进行比较取较大值
+ dp[i] = max(dp[i], dp[i - j] * dp[j])
+
+ return dp[n] # 返回整数拆分的最大乘积结果
+
+```
+贪心
+```python
+class Solution:
+ def integerBreak(self, n):
+ if n == 2: # 当n等于2时,只有一种拆分方式:1+1=2,乘积为1
+ return 1
+ if n == 3: # 当n等于3时,只有一种拆分方式:1+1+1=3,乘积为1
+ return 2
+ if n == 4: # 当n等于4时,有两种拆分方式:2+2=4和1+1+1+1=4,乘积都为4
+ return 4
+ result = 1
+ while n > 4:
+ result *= 3 # 每次乘以3,因为3的乘积比其他数字更大
+ n -= 3 # 每次减去3
+ result *= n # 将剩余的n乘以最后的结果
+ return result
+
+```
### Go
```go
func integerBreak(n int) int {
diff --git a/problems/0376.摆动序列.md b/problems/0376.摆动序列.md
index ff388b55..08de23ae 100644
--- a/problems/0376.摆动序列.md
+++ b/problems/0376.摆动序列.md
@@ -99,7 +99,7 @@
这里我们可以写死,就是 如果只有两个元素,且元素不同,那么结果为 2。
-不写死的话,如果和我们的判断规则结合在一起呢?
+不写死的话,如何和我们的判断规则结合在一起呢?
可以假设,数组最前面还有一个数字,那这个数字应该是什么呢?
@@ -305,21 +305,43 @@ class Solution {
### Python
-**贪心**
+贪心(版本一)
+
+```python
+class Solution:
+ def wiggleMaxLength(self, nums):
+ if len(nums) <= 1:
+ return len(nums) # 如果数组长度为0或1,则返回数组长度
+ curDiff = 0 # 当前一对元素的差值
+ preDiff = 0 # 前一对元素的差值
+ result = 1 # 记录峰值的个数,初始为1(默认最右边的元素被视为峰值)
+ for i in range(len(nums) - 1):
+ curDiff = nums[i + 1] - nums[i] # 计算下一个元素与当前元素的差值
+ # 如果遇到一个峰值
+ if (preDiff <= 0 and curDiff > 0) or (preDiff >= 0 and curDiff < 0):
+ result += 1 # 峰值个数加1
+ preDiff = curDiff # 注意这里,只在摆动变化的时候更新preDiff
+ return result # 返回最长摆动子序列的长度
+
+```
+贪心(版本二)
```python
class Solution:
def wiggleMaxLength(self, nums: List[int]) -> int:
- preC,curC,res = 0,0,1 #题目里nums长度大于等于1,当长度为1时,其实到不了for循环里去,所以不用考虑nums长度
+ if len(nums) <= 1:
+ return len(nums) # 如果数组长度为0或1,则返回数组长度
+ preDiff,curDiff ,result = 0,0,1 #题目里nums长度大于等于1,当长度为1时,其实到不了for循环里去,所以不用考虑nums长度
for i in range(len(nums) - 1):
- curC = nums[i + 1] - nums[i]
- if curC * preC <= 0 and curC !=0: #差值为0时,不算摆动
- res += 1
- preC = curC #如果当前差值和上一个差值为一正一负时,才需要用当前差值替代上一个差值
- return res
+ curDiff = nums[i + 1] - nums[i]
+ if curDiff * preDiff <= 0 and curDiff !=0: #差值为0时,不算摆动
+ result += 1
+ preDiff = curDiff #如果当前差值和上一个差值为一正一负时,才需要用当前差值替代上一个差值
+ return result
+
```
-**动态规划**
+动态规划(版本一)
```python
class Solution:
@@ -341,25 +363,44 @@ class Solution:
return max(dp[-1][0], dp[-1][1])
```
+动态规划(版本二)
+
```python
class Solution:
- def wiggleMaxLength(self, nums: List[int]) -> int:
- # up i作为波峰最长的序列长度
- # down i作为波谷最长的序列长度
- n = len(nums)
- # 长度为0和1的直接返回长度
- if n<2: return n
- for i in range(1,n):
- if nums[i]>nums[i-1]:
- # nums[i] 为波峰,1. 前面是波峰,up值不变,2. 前面是波谷,down值加1
- # 目前up值取两者的较大值(其实down+1即可,可以推理前一步down和up最多相差1,所以down+1>=up)
- up = max(up, down+1)
- elif nums[i]
diff --git a/problems/0455.分发饼干.md b/problems/0455.分发饼干.md
index c4f81035..ce1987ef 100644
--- a/problems/0455.分发饼干.md
+++ b/problems/0455.分发饼干.md
@@ -177,32 +177,33 @@ class Solution {
```
### Python
-
+贪心 大饼干优先
```python
class Solution:
- # 思路1:优先考虑小胃口
- def findContentChildren(self, g: List[int], s: List[int]) -> int:
- g.sort()
- s.sort()
- res = 0
- for i in range(len(s)):
- if res
diff --git a/problems/0501.二叉搜索树中的众数.md b/problems/0501.二叉搜索树中的众数.md
index b7ef606f..1da32343 100644
--- a/problems/0501.二叉搜索树中的众数.md
+++ b/problems/0501.二叉搜索树中的众数.md
@@ -472,11 +472,63 @@ class Solution {
}
}
```
+統一迭代法
+```Java
+class Solution {
+ public int[] findMode(TreeNode root) {
+ int count = 0;
+ int maxCount = 0;
+ TreeNode pre = null;
+ LinkedList