Merge branch 'master' of github.com:youngyangyang04/leetcode-master
This commit is contained in:
commit
46a81f2073
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
那么我们就应该想到使用哈希法了。
|
||||
|
||||
因为本地,我们不仅要知道元素有没有遍历过,还有知道这个元素对应的下标,**需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适**。
|
||||
因为本地,我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,**需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适**。
|
||||
|
||||
再来看一下使用数组和set来做哈希法的局限。
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
```
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
|
|
|||
|
|
@ -191,8 +191,8 @@ public:
|
|||
};
|
||||
```
|
||||
|
||||
* 时间复杂度:$O(\log n)$
|
||||
* 时间复杂度:$O(1)$
|
||||
* 时间复杂度:O(log n)
|
||||
* 空间复杂度:O(1)
|
||||
|
||||
## 总结
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
主要在于如何在回溯中去重
|
||||
|
||||
|
|
|
|||
|
|
@ -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<len(nums): result[i+j]=min(result[i+j],result[i]+1)
|
||||
#print(result) #打印数组
|
||||
return result[-1]
|
||||
result = [10**4+1] * len(nums) # 初始化结果数组,初始值为一个较大的数
|
||||
result[0] = 0 # 起始位置的步数为0
|
||||
|
||||
for i in range(len(nums)): # 遍历数组
|
||||
for j in range(nums[i] + 1): # 在当前位置能够跳跃的范围内遍历
|
||||
if i + j < len(nums): # 确保下一跳的位置不超过数组范围
|
||||
result[i + j] = min(result[i + j], result[i] + 1) # 更新到达下一跳位置的最小步数
|
||||
|
||||
return result[-1] # 返回到达最后一个位置的最小步数
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -215,68 +215,27 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python
|
||||
**回溯**
|
||||
回溯 使用used
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.path = []
|
||||
self.paths = []
|
||||
def permute(self, nums):
|
||||
result = []
|
||||
self.backtracking(nums, [], [False] * len(nums), result)
|
||||
return result
|
||||
|
||||
def permute(self, nums: List[int]) -> List[List[int]]:
|
||||
'''
|
||||
因为本题排列是有序的,这意味着同一层的元素可以重复使用,但同一树枝上不能重复使用(usage_list)
|
||||
所以处理排列问题每层都需要从头搜索,故不再使用start_index
|
||||
'''
|
||||
usage_list = [False] * len(nums)
|
||||
self.backtracking(nums, usage_list)
|
||||
return self.paths
|
||||
|
||||
def backtracking(self, nums: List[int], usage_list: List[bool]) -> None:
|
||||
# Base Case本题求叶子节点
|
||||
if len(self.path) == len(nums):
|
||||
self.paths.append(self.path[:])
|
||||
def backtracking(self, nums, path, used, result):
|
||||
if len(path) == len(nums):
|
||||
result.append(path[:])
|
||||
return
|
||||
|
||||
# 单层递归逻辑
|
||||
for i in range(0, len(nums)): # 从头开始搜索
|
||||
# 若遇到self.path里已收录的元素,跳过
|
||||
if usage_list[i] == True:
|
||||
for i in range(len(nums)):
|
||||
if used[i]:
|
||||
continue
|
||||
usage_list[i] = True
|
||||
self.path.append(nums[i])
|
||||
self.backtracking(nums, usage_list) # 纵向传递使用信息,去重
|
||||
self.path.pop()
|
||||
usage_list[i] = False
|
||||
```
|
||||
**回溯+丢掉usage_list**
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.path = []
|
||||
self.paths = []
|
||||
used[i] = True
|
||||
path.append(nums[i])
|
||||
self.backtracking(nums, path, used, result)
|
||||
path.pop()
|
||||
used[i] = False
|
||||
|
||||
def permute(self, nums: List[int]) -> List[List[int]]:
|
||||
'''
|
||||
因为本题排列是有序的,这意味着同一层的元素可以重复使用,但同一树枝上不能重复使用
|
||||
所以处理排列问题每层都需要从头搜索,故不再使用start_index
|
||||
'''
|
||||
self.backtracking(nums)
|
||||
return self.paths
|
||||
|
||||
def backtracking(self, nums: List[int]) -> None:
|
||||
# Base Case本题求叶子节点
|
||||
if len(self.path) == len(nums):
|
||||
self.paths.append(self.path[:])
|
||||
return
|
||||
|
||||
# 单层递归逻辑
|
||||
for i in range(0, len(nums)): # 从头开始搜索
|
||||
# 若遇到self.path里已收录的元素,跳过
|
||||
if nums[i] in self.path:
|
||||
continue
|
||||
self.path.append(nums[i])
|
||||
self.backtracking(nums)
|
||||
self.path.pop()
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -223,28 +223,25 @@ class Solution {
|
|||
|
||||
```python
|
||||
class Solution:
|
||||
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
|
||||
# res用来存放结果
|
||||
if not nums: return []
|
||||
res = []
|
||||
used = [0] * len(nums)
|
||||
def backtracking(nums, used, path):
|
||||
# 终止条件
|
||||
if len(path) == len(nums):
|
||||
res.append(path.copy())
|
||||
return
|
||||
for i in range(len(nums)):
|
||||
if not used[i]:
|
||||
if i>0 and nums[i] == nums[i-1] and not used[i-1]:
|
||||
continue
|
||||
used[i] = 1
|
||||
path.append(nums[i])
|
||||
backtracking(nums, used, path)
|
||||
path.pop()
|
||||
used[i] = 0
|
||||
# 记得给nums排序
|
||||
backtracking(sorted(nums),used,[])
|
||||
return res
|
||||
def permuteUnique(self, nums):
|
||||
nums.sort() # 排序
|
||||
result = []
|
||||
self.backtracking(nums, [], [False] * len(nums), result)
|
||||
return result
|
||||
|
||||
def backtracking(self, nums, path, used, result):
|
||||
if len(path) == len(nums):
|
||||
result.append(path[:])
|
||||
return
|
||||
for i in range(len(nums)):
|
||||
if (i > 0 and nums[i] == nums[i - 1] and not used[i - 1]) or used[i]:
|
||||
continue
|
||||
used[i] = True
|
||||
path.append(nums[i])
|
||||
self.backtracking(nums, path, used, result)
|
||||
path.pop()
|
||||
used[i] = False
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -351,48 +351,47 @@ class Solution {
|
|||
```python
|
||||
class Solution:
|
||||
def solveNQueens(self, n: int) -> List[List[str]]:
|
||||
if not n: return []
|
||||
board = [['.'] * n for _ in range(n)]
|
||||
res = []
|
||||
def isVaild(board,row, col):
|
||||
#判断同一列是否冲突
|
||||
for i in range(len(board)):
|
||||
if board[i][col] == 'Q':
|
||||
return False
|
||||
# 判断左上角是否冲突
|
||||
i = row -1
|
||||
j = col -1
|
||||
while i>=0 and j>=0:
|
||||
if board[i][j] == 'Q':
|
||||
return False
|
||||
i -= 1
|
||||
j -= 1
|
||||
# 判断右上角是否冲突
|
||||
i = row - 1
|
||||
j = col + 1
|
||||
while i>=0 and j < len(board):
|
||||
if board[i][j] == 'Q':
|
||||
return False
|
||||
i -= 1
|
||||
j += 1
|
||||
return True
|
||||
result = [] # 存储最终结果的二维字符串数组
|
||||
|
||||
chessboard = ['.' * n for _ in range(n)] # 初始化棋盘
|
||||
self.backtracking(n, 0, chessboard, result) # 回溯求解
|
||||
return [[''.join(row) for row in solution] for solution in result] # 返回结果集
|
||||
|
||||
def backtracking(self, n: int, row: int, chessboard: List[str], result: List[List[str]]) -> None:
|
||||
if row == n:
|
||||
result.append(chessboard[:]) # 棋盘填满,将当前解加入结果集
|
||||
return
|
||||
|
||||
for col in range(n):
|
||||
if self.isValid(row, col, chessboard):
|
||||
chessboard[row] = chessboard[row][:col] + 'Q' + chessboard[row][col+1:] # 放置皇后
|
||||
self.backtracking(n, row + 1, chessboard, result) # 递归到下一行
|
||||
chessboard[row] = chessboard[row][:col] + '.' + chessboard[row][col+1:] # 回溯,撤销当前位置的皇后
|
||||
|
||||
def isValid(self, row: int, col: int, chessboard: List[str]) -> bool:
|
||||
# 检查列
|
||||
for i in range(row):
|
||||
if chessboard[i][col] == 'Q':
|
||||
return False # 当前列已经存在皇后,不合法
|
||||
|
||||
# 检查 45 度角是否有皇后
|
||||
i, j = row - 1, col - 1
|
||||
while i >= 0 and j >= 0:
|
||||
if chessboard[i][j] == 'Q':
|
||||
return False # 左上方向已经存在皇后,不合法
|
||||
i -= 1
|
||||
j -= 1
|
||||
|
||||
# 检查 135 度角是否有皇后
|
||||
i, j = row - 1, col + 1
|
||||
while i >= 0 and j < len(chessboard):
|
||||
if chessboard[i][j] == 'Q':
|
||||
return False # 右上方向已经存在皇后,不合法
|
||||
i -= 1
|
||||
j += 1
|
||||
|
||||
return True # 当前位置合法
|
||||
|
||||
def backtracking(board, row, n):
|
||||
# 如果走到最后一行,说明已经找到一个解
|
||||
if row == n:
|
||||
temp_res = []
|
||||
for temp in board:
|
||||
temp_str = "".join(temp)
|
||||
temp_res.append(temp_str)
|
||||
res.append(temp_res)
|
||||
for col in range(n):
|
||||
if not isVaild(board, row, col):
|
||||
continue
|
||||
board[row][col] = 'Q'
|
||||
backtracking(board, row+1, n)
|
||||
board[row][col] = '.'
|
||||
backtracking(board, 0, n)
|
||||
return res
|
||||
```
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -198,21 +198,35 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python
|
||||
|
||||
暴力法
|
||||
```python
|
||||
class Solution:
|
||||
def maxSubArray(self, nums: List[int]) -> int:
|
||||
result = -float('inf')
|
||||
def maxSubArray(self, nums):
|
||||
result = float('-inf') # 初始化结果为负无穷大
|
||||
count = 0
|
||||
for i in range(len(nums)): # 设置起始位置
|
||||
count = 0
|
||||
for j in range(i, len(nums)): # 从起始位置i开始遍历寻找最大值
|
||||
count += nums[j]
|
||||
result = max(count, result) # 更新最大值
|
||||
return result
|
||||
|
||||
```
|
||||
```python
|
||||
class Solution:
|
||||
def maxSubArray(self, nums):
|
||||
result = float('-inf') # 初始化结果为负无穷大
|
||||
count = 0
|
||||
for i in range(len(nums)):
|
||||
count += nums[i]
|
||||
if count > result:
|
||||
if count > result: # 取区间累计的最大值(相当于不断确定最大子序终止位置)
|
||||
result = count
|
||||
if count <= 0:
|
||||
if count <= 0: # 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和
|
||||
count = 0
|
||||
return result
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
### Go
|
||||
|
||||
```go
|
||||
|
|
|
|||
|
|
@ -144,8 +144,6 @@ Python:
|
|||
```python
|
||||
class Solution:
|
||||
def maxSubArray(self, nums: List[int]) -> int:
|
||||
if len(nums) == 0:
|
||||
return 0
|
||||
dp = [0] * len(nums)
|
||||
dp[0] = nums[0]
|
||||
result = dp[0]
|
||||
|
|
|
|||
|
|
@ -140,18 +140,24 @@ class Solution {
|
|||
### Python
|
||||
```python
|
||||
class Solution:
|
||||
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
|
||||
if len(intervals) == 0: return intervals
|
||||
intervals.sort(key=lambda x: x[0])
|
||||
def merge(self, intervals):
|
||||
result = []
|
||||
result.append(intervals[0])
|
||||
if len(intervals) == 0:
|
||||
return result # 区间集合为空直接返回
|
||||
|
||||
intervals.sort(key=lambda x: x[0]) # 按照区间的左边界进行排序
|
||||
|
||||
result.append(intervals[0]) # 第一个区间可以直接放入结果集中
|
||||
|
||||
for i in range(1, len(intervals)):
|
||||
last = result[-1]
|
||||
if last[1] >= intervals[i][0]:
|
||||
result[-1] = [last[0], max(last[1], intervals[i][1])]
|
||||
if result[-1][1] >= intervals[i][0]: # 发现重叠区间
|
||||
# 合并区间,只需要更新结果集最后一个区间的右边界,因为根据排序,左边界已经是最小的
|
||||
result[-1][1] = max(result[-1][1], intervals[i][1])
|
||||
else:
|
||||
result.append(intervals[i])
|
||||
result.append(intervals[i]) # 区间不重叠
|
||||
|
||||
return result
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -287,17 +287,70 @@ public:
|
|||
```
|
||||
|
||||
### Python
|
||||
|
||||
递归
|
||||
```python
|
||||
class Solution: # 动态规划
|
||||
class Solution:
|
||||
def uniquePaths(self, m: int, n: int) -> int:
|
||||
dp = [[1 for i in range(n)] for j in range(m)]
|
||||
if m == 1 or n == 1:
|
||||
return 1
|
||||
return self.uniquePaths(m - 1, n) + self.uniquePaths(m, n - 1)
|
||||
|
||||
```
|
||||
动态规划(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def uniquePaths(self, m: int, n: int) -> int:
|
||||
# 创建一个二维列表用于存储唯一路径数
|
||||
dp = [[0] * n for _ in range(m)]
|
||||
|
||||
# 设置第一行和第一列的基本情况
|
||||
for i in range(m):
|
||||
dp[i][0] = 1
|
||||
for j in range(n):
|
||||
dp[0][j] = 1
|
||||
|
||||
# 计算每个单元格的唯一路径数
|
||||
for i in range(1, m):
|
||||
for j in range(1, n):
|
||||
dp[i][j] = dp[i][j - 1] + dp[i - 1][j]
|
||||
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
|
||||
|
||||
# 返回右下角单元格的唯一路径数
|
||||
return dp[m - 1][n - 1]
|
||||
```
|
||||
|
||||
```
|
||||
动态规划(版本二)
|
||||
```python
|
||||
class Solution:
|
||||
def uniquePaths(self, m: int, n: int) -> int:
|
||||
# 创建一个一维列表用于存储每列的唯一路径数
|
||||
dp = [1] * n
|
||||
|
||||
# 计算每个单元格的唯一路径数
|
||||
for j in range(1, m):
|
||||
for i in range(1, n):
|
||||
dp[i] += dp[i - 1]
|
||||
|
||||
# 返回右下角单元格的唯一路径数
|
||||
return dp[n - 1]
|
||||
```
|
||||
数论
|
||||
```python
|
||||
class Solution:
|
||||
def uniquePaths(self, m: int, n: int) -> int:
|
||||
numerator = 1 # 分子
|
||||
denominator = m - 1 # 分母
|
||||
count = m - 1 # 计数器,表示剩余需要计算的乘积项个数
|
||||
t = m + n - 2 # 初始乘积项
|
||||
while count > 0:
|
||||
numerator *= t # 计算乘积项的分子部分
|
||||
t -= 1 # 递减乘积项
|
||||
while denominator != 0 and numerator % denominator == 0:
|
||||
numerator //= denominator # 约简分子
|
||||
denominator -= 1 # 递减分母
|
||||
count -= 1 # 计数器减1,继续下一项的计算
|
||||
return numerator # 返回最终的唯一路径数
|
||||
|
||||
```
|
||||
### Go
|
||||
|
||||
```Go
|
||||
|
|
|
|||
|
|
@ -271,69 +271,130 @@ class Solution {
|
|||
|
||||
|
||||
### Python
|
||||
|
||||
动态规划(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
|
||||
# 构造一个DP table
|
||||
row = len(obstacleGrid)
|
||||
col = len(obstacleGrid[0])
|
||||
dp = [[0 for _ in range(col)] for _ in range(row)]
|
||||
dp[0][0] = 0 if obstacleGrid[0][0] == 1 else 1
|
||||
if dp[0][0] == 0:
|
||||
return 0 # 如果第一个格子就是障碍,return 0
|
||||
# 第一行
|
||||
for i in range(1, col):
|
||||
if obstacleGrid[0][i] == 1:
|
||||
# 遇到障碍物时,直接退出循环,后面默认都是0
|
||||
def uniquePathsWithObstacles(self, obstacleGrid):
|
||||
m = len(obstacleGrid)
|
||||
n = len(obstacleGrid[0])
|
||||
if obstacleGrid[m - 1][n - 1] == 1 or obstacleGrid[0][0] == 1:
|
||||
return 0
|
||||
dp = [[0] * n for _ in range(m)]
|
||||
for i in range(m):
|
||||
if obstacleGrid[i][0] == 0: # 遇到障碍物时,直接退出循环,后面默认都是0
|
||||
dp[i][0] = 1
|
||||
else:
|
||||
break
|
||||
dp[0][i] = 1
|
||||
|
||||
# 第一列
|
||||
for i in range(1, row):
|
||||
if obstacleGrid[i][0] == 1:
|
||||
# 遇到障碍物时,直接退出循环,后面默认都是0
|
||||
for j in range(n):
|
||||
if obstacleGrid[0][j] == 0:
|
||||
dp[0][j] = 1
|
||||
else:
|
||||
break
|
||||
dp[i][0] = 1
|
||||
# print(dp)
|
||||
for i in range(1, m):
|
||||
for j in range(1, n):
|
||||
if obstacleGrid[i][j] == 1:
|
||||
continue
|
||||
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
|
||||
return dp[m - 1][n - 1]
|
||||
|
||||
for i in range(1, row):
|
||||
for j in range(1, col):
|
||||
if obstacleGrid[i][j] == 0:
|
||||
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
|
||||
return dp[-1][-1]
|
||||
```
|
||||
动态规划(版本二)
|
||||
```python
|
||||
class Solution:
|
||||
def uniquePathsWithObstacles(self, obstacleGrid):
|
||||
m = len(obstacleGrid) # 网格的行数
|
||||
n = len(obstacleGrid[0]) # 网格的列数
|
||||
|
||||
if obstacleGrid[m - 1][n - 1] == 1 or obstacleGrid[0][0] == 1:
|
||||
# 如果起点或终点有障碍物,直接返回0
|
||||
return 0
|
||||
|
||||
dp = [[0] * n for _ in range(m)] # 创建一个二维列表用于存储路径数
|
||||
|
||||
# 设置起点的路径数为1
|
||||
dp[0][0] = 1 if obstacleGrid[0][0] == 0 else 0
|
||||
|
||||
# 计算第一列的路径数
|
||||
for i in range(1, m):
|
||||
if obstacleGrid[i][0] == 0:
|
||||
dp[i][0] = dp[i - 1][0]
|
||||
|
||||
# 计算第一行的路径数
|
||||
for j in range(1, n):
|
||||
if obstacleGrid[0][j] == 0:
|
||||
dp[0][j] = dp[0][j - 1]
|
||||
|
||||
# 计算其他位置的路径数
|
||||
for i in range(1, m):
|
||||
for j in range(1, n):
|
||||
if obstacleGrid[i][j] == 1:
|
||||
continue
|
||||
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
|
||||
|
||||
return dp[m - 1][n - 1] # 返回终点的路径数
|
||||
|
||||
|
||||
```
|
||||
动态规划(版本三)
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
"""
|
||||
使用一维dp数组
|
||||
"""
|
||||
def uniquePathsWithObstacles(self, obstacleGrid):
|
||||
if obstacleGrid[0][0] == 1:
|
||||
return 0
|
||||
|
||||
dp = [0] * len(obstacleGrid[0]) # 创建一个一维列表用于存储路径数
|
||||
|
||||
# 初始化第一行的路径数
|
||||
for j in range(len(dp)):
|
||||
if obstacleGrid[0][j] == 1:
|
||||
dp[j] = 0
|
||||
elif j == 0:
|
||||
dp[j] = 1
|
||||
else:
|
||||
dp[j] = dp[j - 1]
|
||||
|
||||
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
|
||||
# 计算其他行的路径数
|
||||
for i in range(1, len(obstacleGrid)):
|
||||
for j in range(len(dp)):
|
||||
if obstacleGrid[i][j] == 1:
|
||||
dp[j] = 0
|
||||
elif j != 0:
|
||||
dp[j] = dp[j] + dp[j - 1]
|
||||
|
||||
return dp[-1] # 返回最后一个元素,即终点的路径数
|
||||
|
||||
```
|
||||
动态规划(版本四)
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def uniquePathsWithObstacles(self, obstacleGrid):
|
||||
if obstacleGrid[0][0] == 1:
|
||||
return 0
|
||||
|
||||
m, n = len(obstacleGrid), len(obstacleGrid[0])
|
||||
|
||||
# 初始化dp数组
|
||||
# 该数组缓存当前行
|
||||
curr = [0] * n
|
||||
|
||||
dp = [0] * n # 创建一个一维列表用于存储路径数
|
||||
|
||||
# 初始化第一行的路径数
|
||||
for j in range(n):
|
||||
if obstacleGrid[0][j] == 1:
|
||||
break
|
||||
curr[j] = 1
|
||||
dp[j] = 1
|
||||
|
||||
for i in range(1, m): # 从第二行开始
|
||||
for j in range(n): # 从第一列开始,因为第一列可能有障碍物
|
||||
# 有障碍物处无法通行,状态就设成0
|
||||
# 计算其他行的路径数
|
||||
for i in range(1, m):
|
||||
if obstacleGrid[i][0] == 1:
|
||||
dp[0] = 0
|
||||
for j in range(1, n):
|
||||
if obstacleGrid[i][j] == 1:
|
||||
curr[j] = 0
|
||||
elif j > 0:
|
||||
# 等价于
|
||||
# dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
|
||||
curr[j] = curr[j] + curr[j - 1]
|
||||
# 隐含的状态更新
|
||||
# dp[i][0] = dp[i - 1][0]
|
||||
dp[j] = 0
|
||||
else:
|
||||
dp[j] += dp[j - 1]
|
||||
|
||||
return dp[-1] # 返回最后一个元素,即终点的路径数
|
||||
|
||||
return curr[n - 1]
|
||||
```
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -251,32 +251,66 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python
|
||||
|
||||
动态规划(版本一)
|
||||
```python
|
||||
# 空间复杂度为O(n)版本
|
||||
class Solution:
|
||||
def climbStairs(self, n: int) -> int:
|
||||
# dp[i] 为第 i 阶楼梯有多少种方法爬到楼顶
|
||||
dp = [0]*(n+1)
|
||||
dp[0] = 1
|
||||
if n <= 1:
|
||||
return n
|
||||
|
||||
dp = [0] * (n + 1)
|
||||
dp[1] = 1
|
||||
for i in range(2, n+1):
|
||||
dp[i] = dp[i-1] + dp[i-2]
|
||||
dp[2] = 2
|
||||
|
||||
for i in range(3, n + 1):
|
||||
dp[i] = dp[i - 1] + dp[i - 2]
|
||||
|
||||
return dp[n]
|
||||
|
||||
```
|
||||
动态规划(版本二)
|
||||
```python
|
||||
|
||||
# 空间复杂度为O(3)版本
|
||||
class Solution:
|
||||
def climbStairs(self, n: int) -> int:
|
||||
if n <= 1:
|
||||
return n
|
||||
|
||||
dp = [0] * 3
|
||||
dp[1] = 1
|
||||
dp[2] = 2
|
||||
|
||||
for i in range(3, n + 1):
|
||||
total = dp[1] + dp[2]
|
||||
dp[1] = dp[2]
|
||||
dp[2] = total
|
||||
|
||||
return dp[2]
|
||||
|
||||
```
|
||||
动态规划(版本三)
|
||||
```python
|
||||
|
||||
# 空间复杂度为O(1)版本
|
||||
class Solution:
|
||||
def climbStairs(self, n: int) -> int:
|
||||
dp = [0]*(n+1)
|
||||
dp[0] = 1
|
||||
dp[1] = 1
|
||||
for i in range(2,n+1):
|
||||
tmp = dp[0] + dp[1]
|
||||
dp[0] = dp[1]
|
||||
dp[1] = tmp
|
||||
return dp[1]
|
||||
```
|
||||
if n <= 1:
|
||||
return n
|
||||
|
||||
prev1 = 1
|
||||
prev2 = 2
|
||||
|
||||
for i in range(3, n + 1):
|
||||
total = prev1 + prev2
|
||||
prev1 = prev2
|
||||
prev2 = total
|
||||
|
||||
return prev2
|
||||
|
||||
|
||||
```
|
||||
### Go
|
||||
```Go
|
||||
func climbStairs(n int) int {
|
||||
|
|
|
|||
|
|
@ -381,68 +381,42 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python
|
||||
|
||||
未剪枝优化
|
||||
```python
|
||||
class Solution(object):
|
||||
def combine(self, n, k):
|
||||
"""
|
||||
:type n: int
|
||||
:type k: int
|
||||
:rtype: List[List[int]]
|
||||
"""
|
||||
result = []
|
||||
path = []
|
||||
def backtracking(n, k, startidx):
|
||||
if len(path) == k:
|
||||
result.append(path[:])
|
||||
return
|
||||
|
||||
# 剪枝, 最后k - len(path)个节点直接构造结果,无需递归
|
||||
last_startidx = n - (k - len(path)) + 1
|
||||
|
||||
for x in range(startidx, last_startidx + 1):
|
||||
path.append(x)
|
||||
backtracking(n, k, x + 1) # 递归
|
||||
path.pop() # 回溯
|
||||
|
||||
backtracking(n, k, 1)
|
||||
class Solution:
|
||||
def combine(self, n: int, k: int) -> List[List[int]]:
|
||||
result = [] # 存放结果集
|
||||
self.backtracking(n, k, 1, [], result)
|
||||
return result
|
||||
def backtracking(self, n, k, startIndex, path, result):
|
||||
if len(path) == k:
|
||||
result.append(path[:])
|
||||
return
|
||||
for i in range(startIndex, n + 1): # 需要优化的地方
|
||||
path.append(i) # 处理节点
|
||||
self.backtracking(n, k, i + 1, path, result)
|
||||
path.pop() # 回溯,撤销处理的节点
|
||||
|
||||
```
|
||||
|
||||
|
||||
剪枝优化:
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def combine(self, n: int, k: int) -> List[List[int]]:
|
||||
res = []
|
||||
path = []
|
||||
def backtrack(n, k, StartIndex):
|
||||
if len(path) == k:
|
||||
res.append(path[:])
|
||||
return
|
||||
for i in range(StartIndex, n + 1):
|
||||
path.append(i)
|
||||
backtrack(n, k, i+1)
|
||||
path.pop()
|
||||
backtrack(n, k, 1)
|
||||
return res
|
||||
```
|
||||
result = [] # 存放结果集
|
||||
self.backtracking(n, k, 1, [], result)
|
||||
return result
|
||||
def backtracking(self, n, k, startIndex, path, result):
|
||||
if len(path) == k:
|
||||
result.append(path[:])
|
||||
return
|
||||
for i in range(startIndex, n - (k - len(path)) + 2): # 优化的地方
|
||||
path.append(i) # 处理节点
|
||||
self.backtracking(n, k, i + 1, path, result)
|
||||
path.pop() # 回溯,撤销处理的节点
|
||||
|
||||
剪枝:
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def combine(self, n: int, k: int) -> List[List[int]]:
|
||||
res=[] #存放符合条件结果的集合
|
||||
path=[] #用来存放符合条件结果
|
||||
def backtrack(n,k,startIndex):
|
||||
if len(path) == k:
|
||||
res.append(path[:])
|
||||
return
|
||||
for i in range(startIndex,n-(k-len(path))+2): #优化的地方
|
||||
path.append(i) #处理节点
|
||||
backtrack(n,k,i+1) #递归
|
||||
path.pop() #回溯,撤销处理的节点
|
||||
backtrack(n,k,1)
|
||||
return res
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -183,18 +183,21 @@ Python:
|
|||
```python
|
||||
class Solution:
|
||||
def combine(self, n: int, k: int) -> List[List[int]]:
|
||||
res=[] #存放符合条件结果的集合
|
||||
path=[] #用来存放符合条件结果
|
||||
def backtrack(n,k,startIndex):
|
||||
if len(path) == k:
|
||||
res.append(path[:])
|
||||
return
|
||||
for i in range(startIndex,n-(k-len(path))+2): #优化的地方
|
||||
path.append(i) #处理节点
|
||||
backtrack(n,k,i+1) #递归
|
||||
path.pop() #回溯,撤销处理的节点
|
||||
backtrack(n,k,1)
|
||||
return res
|
||||
result = [] # 存放结果集
|
||||
self.backtracking(n, k, 1, [], result)
|
||||
return result
|
||||
def backtracking(self, n, k, startIndex, path, result):
|
||||
if len(path) == k:
|
||||
result.append(path[:])
|
||||
return
|
||||
for i in range(startIndex, n - (k - len(path)) + 2): # 优化的地方
|
||||
path.append(i) # 处理节点
|
||||
self.backtracking(n, k, i + 1, path, result)
|
||||
path.pop() # 回溯,撤销处理的节点
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
Go:
|
||||
```Go
|
||||
|
|
|
|||
|
|
@ -208,28 +208,20 @@ class Solution {
|
|||
## Python
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.path: List[int] = []
|
||||
self.paths: List[List[int]] = []
|
||||
def subsets(self, nums):
|
||||
result = []
|
||||
path = []
|
||||
self.backtracking(nums, 0, path, result)
|
||||
return result
|
||||
|
||||
def subsets(self, nums: List[int]) -> List[List[int]]:
|
||||
self.paths.clear()
|
||||
self.path.clear()
|
||||
self.backtracking(nums, 0)
|
||||
return self.paths
|
||||
|
||||
def backtracking(self, nums: List[int], start_index: int) -> None:
|
||||
# 收集子集,要先于终止判断
|
||||
self.paths.append(self.path[:])
|
||||
# Base Case
|
||||
if start_index == len(nums):
|
||||
return
|
||||
|
||||
# 单层递归逻辑
|
||||
for i in range(start_index, len(nums)):
|
||||
self.path.append(nums[i])
|
||||
self.backtracking(nums, i+1)
|
||||
self.path.pop() # 回溯
|
||||
def backtracking(self, nums, startIndex, path, result):
|
||||
result.append(path[:]) # 收集子集,要放在终止添加的上面,否则会漏掉自己
|
||||
# if startIndex >= len(nums): # 终止条件可以不加
|
||||
# return
|
||||
for i in range(startIndex, len(nums)):
|
||||
path.append(nums[i])
|
||||
self.backtracking(nums, i + 1, path, result)
|
||||
path.pop()
|
||||
```
|
||||
|
||||
## Go
|
||||
|
|
|
|||
|
|
@ -238,86 +238,84 @@ class Solution {
|
|||
}
|
||||
```
|
||||
|
||||
### Python
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.paths = []
|
||||
self.path = []
|
||||
|
||||
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
|
||||
nums.sort()
|
||||
self.backtracking(nums, 0)
|
||||
return self.paths
|
||||
|
||||
def backtracking(self, nums: List[int], start_index: int) -> None:
|
||||
# ps.空集合仍符合要求
|
||||
self.paths.append(self.path[:])
|
||||
# Base Case
|
||||
if start_index == len(nums):
|
||||
return
|
||||
|
||||
# 单层递归逻辑
|
||||
for i in range(start_index, len(nums)):
|
||||
if i > start_index and nums[i] == nums[i-1]:
|
||||
# 当前后元素值相同时,跳入下一个循环,去重
|
||||
continue
|
||||
self.path.append(nums[i])
|
||||
self.backtracking(nums, i+1)
|
||||
self.path.pop()
|
||||
```
|
||||
|
||||
#### Python3
|
||||
|
||||
不使用used数组
|
||||
回溯 利用used数组去重
|
||||
```python
|
||||
class Solution:
|
||||
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
|
||||
res = []
|
||||
path = []
|
||||
nums.sort() # 去重需要先对数组进行排序
|
||||
|
||||
def backtracking(nums, startIndex):
|
||||
# 终止条件
|
||||
res.append(path[:])
|
||||
if startIndex == len(nums):
|
||||
return
|
||||
|
||||
# for循环
|
||||
for i in range(startIndex, len(nums)):
|
||||
# 数层去重
|
||||
if i > startIndex and nums[i] == nums[i-1]: # 去重
|
||||
continue
|
||||
path.append(nums[i])
|
||||
backtracking(nums, i+1)
|
||||
path.pop()
|
||||
|
||||
backtracking(nums, 0)
|
||||
return res
|
||||
```
|
||||
|
||||
使用used数组
|
||||
```python
|
||||
class Solution:
|
||||
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
|
||||
def subsetsWithDup(self, nums):
|
||||
result = []
|
||||
path = []
|
||||
nums.sort()
|
||||
used = [0] * len(nums)
|
||||
def backtrack(nums, startIdx):
|
||||
result.append(path[:])
|
||||
for i in range(startIdx, len(nums)):
|
||||
if i > startIdx and nums[i] == nums[i-1] and used[i-1] == 0:
|
||||
continue
|
||||
used[i] = 1
|
||||
path.append(nums[i])
|
||||
backtrack(nums, i+1)
|
||||
path.pop()
|
||||
used[i] = 0
|
||||
backtrack(nums, 0)
|
||||
used = [False] * len(nums)
|
||||
nums.sort() # 去重需要排序
|
||||
self.backtracking(nums, 0, used, path, result)
|
||||
return result
|
||||
|
||||
def backtracking(self, nums, startIndex, used, path, result):
|
||||
result.append(path[:]) # 收集子集
|
||||
for i in range(startIndex, len(nums)):
|
||||
# used[i - 1] == True,说明同一树枝 nums[i - 1] 使用过
|
||||
# used[i - 1] == False,说明同一树层 nums[i - 1] 使用过
|
||||
# 而我们要对同一树层使用过的元素进行跳过
|
||||
if i > 0 and nums[i] == nums[i - 1] and not used[i - 1]:
|
||||
continue
|
||||
path.append(nums[i])
|
||||
used[i] = True
|
||||
self.backtracking(nums, i + 1, used, path, result)
|
||||
used[i] = False
|
||||
path.pop()
|
||||
|
||||
```
|
||||
|
||||
回溯 利用集合去重
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def subsetsWithDup(self, nums):
|
||||
result = []
|
||||
path = []
|
||||
nums.sort() # 去重需要排序
|
||||
self.backtracking(nums, 0, path, result)
|
||||
return result
|
||||
|
||||
def backtracking(self, nums, startIndex, path, result):
|
||||
result.append(path[:]) # 收集子集
|
||||
uset = set()
|
||||
for i in range(startIndex, len(nums)):
|
||||
if nums[i] in uset:
|
||||
continue
|
||||
uset.add(nums[i])
|
||||
path.append(nums[i])
|
||||
self.backtracking(nums, i + 1, path, result)
|
||||
path.pop()
|
||||
|
||||
```
|
||||
|
||||
回溯 利用递归的时候下一个startIndex是i+1而不是0去重
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def subsetsWithDup(self, nums):
|
||||
result = []
|
||||
path = []
|
||||
nums.sort() # 去重需要排序
|
||||
self.backtracking(nums, 0, path, result)
|
||||
return result
|
||||
|
||||
def backtracking(self, nums, startIndex, path, result):
|
||||
result.append(path[:]) # 收集子集
|
||||
for i in range(startIndex, len(nums)):
|
||||
# 而我们要对同一树层使用过的元素进行跳过
|
||||
if i > startIndex and nums[i] == nums[i - 1]:
|
||||
continue
|
||||
path.append(nums[i])
|
||||
self.backtracking(nums, i + 1, path, result)
|
||||
path.pop()
|
||||
|
||||
|
||||
```
|
||||
### Go
|
||||
|
||||
```Go
|
||||
|
|
|
|||
|
|
@ -316,6 +316,47 @@ class Solution {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
//方法一:但使用stringBuilder,故优化时间、空间复杂度,因为向字符串插入字符时无需复制整个字符串,从而减少了操作的时间复杂度,也不用开新空间存subString,从而减少了空间复杂度。
|
||||
class Solution {
|
||||
List<String> result = new ArrayList<>();
|
||||
public List<String> restoreIpAddresses(String s) {
|
||||
StringBuilder sb = new StringBuilder(s);
|
||||
backTracking(sb, 0, 0);
|
||||
return result;
|
||||
}
|
||||
private void backTracking(StringBuilder s, int startIndex, int dotCount){
|
||||
if(dotCount == 3){
|
||||
if(isValid(s, startIndex, s.length() - 1)){
|
||||
result.add(s.toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
for(int i = startIndex; i < s.length(); i++){
|
||||
if(isValid(s, startIndex, i)){
|
||||
s.insert(i + 1, '.');
|
||||
backTracking(s, i + 2, dotCount + 1);
|
||||
s.deleteCharAt(i + 1);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//[start, end]
|
||||
private boolean isValid(StringBuilder s, int start, int end){
|
||||
if(start > end)
|
||||
return false;
|
||||
if(s.charAt(start) == '0' && start != end)
|
||||
return false;
|
||||
int num = 0;
|
||||
for(int i = start; i <= end; i++){
|
||||
int digit = s.charAt(i) - '0';
|
||||
num = num * 10 + digit;
|
||||
if(num > 255)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//方法二:比上面的方法时间复杂度低,更好地剪枝,优化时间复杂度
|
||||
class Solution {
|
||||
|
|
@ -360,106 +401,85 @@ class Solution {
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
## python
|
||||
|
||||
python2:
|
||||
```python
|
||||
class Solution(object):
|
||||
def restoreIpAddresses(self, s):
|
||||
"""
|
||||
:type s: str
|
||||
:rtype: List[str]
|
||||
"""
|
||||
ans = []
|
||||
path = []
|
||||
def backtrack(path, startIndex):
|
||||
if len(s) > 12: return []
|
||||
if len(path) == 4:
|
||||
if startIndex == len(s):
|
||||
ans.append(".".join(path[:]))
|
||||
return
|
||||
for i in range(startIndex+1, min(startIndex+4, len(s)+1)): # 剪枝
|
||||
string = s[startIndex:i]
|
||||
if not 0 <= int(string) <= 255:
|
||||
continue
|
||||
if not string == "0" and not string.lstrip('0') == string:
|
||||
continue
|
||||
path.append(string)
|
||||
backtrack(path, i)
|
||||
path.pop()
|
||||
|
||||
backtrack([], 0)
|
||||
return ans
|
||||
```
|
||||
|
||||
python3:
|
||||
回溯(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.result = []
|
||||
|
||||
def restoreIpAddresses(self, s: str) -> List[str]:
|
||||
'''
|
||||
本质切割问题使用回溯搜索法,本题只能切割三次,所以纵向递归总共四层
|
||||
因为不能重复分割,所以需要start_index来记录下一层递归分割的起始位置
|
||||
添加变量point_num来记录逗号的数量[0,3]
|
||||
'''
|
||||
self.result.clear()
|
||||
if len(s) > 12: return []
|
||||
self.backtracking(s, 0, 0)
|
||||
return self.result
|
||||
result = []
|
||||
self.backtracking(s, 0, 0, "", result)
|
||||
return result
|
||||
|
||||
def backtracking(self, s: str, start_index: int, point_num: int) -> None:
|
||||
# Base Case
|
||||
if point_num == 3:
|
||||
if self.is_valid(s, start_index, len(s)-1):
|
||||
self.result.append(s[:])
|
||||
def backtracking(self, s, start_index, point_num, current, result):
|
||||
if point_num == 3: # 逗点数量为3时,分隔结束
|
||||
if self.is_valid(s, start_index, len(s) - 1): # 判断第四段子字符串是否合法
|
||||
current += s[start_index:] # 添加最后一段子字符串
|
||||
result.append(current)
|
||||
return
|
||||
# 单层递归逻辑
|
||||
for i in range(start_index, len(s)):
|
||||
# [start_index, i]就是被截取的子串
|
||||
if self.is_valid(s, start_index, i):
|
||||
s = s[:i+1] + '.' + s[i+1:]
|
||||
self.backtracking(s, i+2, point_num+1) # 在填入.后,下一子串起始后移2位
|
||||
s = s[:i+1] + s[i+2:] # 回溯
|
||||
else:
|
||||
# 若当前被截取的子串大于255或者大于三位数,直接结束本层循环
|
||||
break
|
||||
|
||||
def is_valid(self, s: str, start: int, end: int) -> bool:
|
||||
if start > end: return False
|
||||
# 若数字是0开头,不合法
|
||||
if s[start] == '0' and start != end:
|
||||
return False
|
||||
if not 0 <= int(s[start:end+1]) <= 255:
|
||||
return False
|
||||
return True
|
||||
```
|
||||
|
||||
python3; 简单拼接版本(类似Leetcode131写法):
|
||||
for i in range(start_index, len(s)):
|
||||
if self.is_valid(s, start_index, i): # 判断 [start_index, i] 这个区间的子串是否合法
|
||||
sub = s[start_index:i + 1]
|
||||
self.backtracking(s, i + 1, point_num + 1, current + sub + '.', result)
|
||||
else:
|
||||
break
|
||||
|
||||
def is_valid(self, s, start, end):
|
||||
if start > end:
|
||||
return False
|
||||
if s[start] == '0' and start != end: # 0开头的数字不合法
|
||||
return False
|
||||
num = 0
|
||||
for i in range(start, end + 1):
|
||||
if not s[i].isdigit(): # 遇到非数字字符不合法
|
||||
return False
|
||||
num = num * 10 + int(s[i])
|
||||
if num > 255: # 如果大于255了不合法
|
||||
return False
|
||||
return True
|
||||
|
||||
```
|
||||
回溯(版本二)
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
class Solution:
|
||||
def restoreIpAddresses(self, s: str) -> List[str]:
|
||||
global results, path
|
||||
results = []
|
||||
path = []
|
||||
self.backtracking(s,0)
|
||||
self.backtracking(s, 0, [], results)
|
||||
return results
|
||||
|
||||
def backtracking(self,s,index):
|
||||
global results,path
|
||||
if index == len(s) and len(path)==4:
|
||||
results.append('.'.join(path)) # 在连接时需要中间间隔符号的话就在''中间写上对应的间隔符
|
||||
def backtracking(self, s, index, path, results):
|
||||
if index == len(s) and len(path) == 4:
|
||||
results.append('.'.join(path))
|
||||
return
|
||||
for i in range(index,len(s)):
|
||||
if len(path)>3: break # 剪枝
|
||||
temp = s[index:i+1]
|
||||
if (int(temp)<256 and int(temp)>0 and temp[0]!='0') or (temp=='0'):
|
||||
path.append(temp)
|
||||
self.backtracking(s,i+1)
|
||||
path.pop()
|
||||
|
||||
if len(path) > 4: # 剪枝
|
||||
return
|
||||
|
||||
for i in range(index, min(index + 3, len(s))):
|
||||
if self.is_valid(s, index, i):
|
||||
sub = s[index:i+1]
|
||||
path.append(sub)
|
||||
self.backtracking(s, i+1, path, results)
|
||||
path.pop()
|
||||
|
||||
def is_valid(self, s, start, end):
|
||||
if start > end:
|
||||
return False
|
||||
if s[start] == '0' and start != end: # 0开头的数字不合法
|
||||
return False
|
||||
num = int(s[start:end+1])
|
||||
return 0 <= num <= 255
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Go
|
||||
|
||||
```go
|
||||
|
|
|
|||
|
|
@ -197,12 +197,13 @@ class Solution {
|
|||
```python
|
||||
class Solution:
|
||||
def numTrees(self, n: int) -> int:
|
||||
dp = [0] * (n + 1)
|
||||
dp[0], dp[1] = 1, 1
|
||||
for i in range(2, n + 1):
|
||||
for j in range(1, i + 1):
|
||||
dp[i] += dp[j - 1] * dp[i - j]
|
||||
return dp[-1]
|
||||
dp = [0] * (n + 1) # 创建一个长度为n+1的数组,初始化为0
|
||||
dp[0] = 1 # 当n为0时,只有一种情况,即空树,所以dp[0] = 1
|
||||
for i in range(1, n + 1): # 遍历从1到n的每个数字
|
||||
for j in range(1, i + 1): # 对于每个数字i,计算以i为根节点的二叉搜索树的数量
|
||||
dp[i] += dp[j - 1] * dp[i - j] # 利用动态规划的思想,累加左子树和右子树的组合数量
|
||||
return dp[n] # 返回以1到n为节点的二叉搜索树的总数量
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -371,117 +371,113 @@ class Solution {
|
|||
|
||||
## Python
|
||||
|
||||
**递归** - 利用BST中序遍历特性,把树"压缩"成数组
|
||||
递归法(版本一)利用中序递增性质,转换成数组
|
||||
```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 isValidBST(self, root: TreeNode) -> bool:
|
||||
# 思路: 利用BST中序遍历的特性.
|
||||
# 中序遍历输出的二叉搜索树节点的数值是有序序列
|
||||
candidate_list = []
|
||||
|
||||
def __traverse(root: TreeNode) -> None:
|
||||
nonlocal candidate_list
|
||||
if not root:
|
||||
return
|
||||
__traverse(root.left)
|
||||
candidate_list.append(root.val)
|
||||
__traverse(root.right)
|
||||
|
||||
def __is_sorted(nums: list) -> bool:
|
||||
for i in range(1, len(nums)):
|
||||
if nums[i] <= nums[i - 1]: # ⚠️ 注意: Leetcode定义二叉搜索树中不能有重复元素
|
||||
return False
|
||||
return True
|
||||
|
||||
__traverse(root)
|
||||
res = __is_sorted(candidate_list)
|
||||
|
||||
return res
|
||||
```
|
||||
def __init__(self):
|
||||
self.vec = []
|
||||
|
||||
**递归** - 标准做法
|
||||
def traversal(self, root):
|
||||
if root is None:
|
||||
return
|
||||
self.traversal(root.left)
|
||||
self.vec.append(root.val) # 将二叉搜索树转换为有序数组
|
||||
self.traversal(root.right)
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def isValidBST(self, root: TreeNode) -> bool:
|
||||
# 规律: BST的中序遍历节点数值是从小到大.
|
||||
cur_max = -float("INF")
|
||||
def __isValidBST(root: TreeNode) -> bool:
|
||||
nonlocal cur_max
|
||||
|
||||
if not root:
|
||||
return True
|
||||
|
||||
is_left_valid = __isValidBST(root.left)
|
||||
if cur_max < root.val:
|
||||
cur_max = root.val
|
||||
else:
|
||||
def isValidBST(self, root):
|
||||
self.vec = [] # 清空数组
|
||||
self.traversal(root)
|
||||
for i in range(1, len(self.vec)):
|
||||
# 注意要小于等于,搜索树里不能有相同元素
|
||||
if self.vec[i] <= self.vec[i - 1]:
|
||||
return False
|
||||
is_right_valid = __isValidBST(root.right)
|
||||
|
||||
return is_left_valid and is_right_valid
|
||||
return __isValidBST(root)
|
||||
return True
|
||||
|
||||
```
|
||||
**递归** - 避免初始化最小值做法:
|
||||
|
||||
递归法(版本二)设定极小值,进行比较
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def isValidBST(self, root: TreeNode) -> bool:
|
||||
# 规律: BST的中序遍历节点数值是从小到大.
|
||||
pre = None
|
||||
def __isValidBST(root: TreeNode) -> bool:
|
||||
nonlocal pre
|
||||
|
||||
if not root:
|
||||
return True
|
||||
|
||||
is_left_valid = __isValidBST(root.left)
|
||||
if pre and pre.val>=root.val: return False
|
||||
pre = root
|
||||
is_right_valid = __isValidBST(root.right)
|
||||
|
||||
return is_left_valid and is_right_valid
|
||||
return __isValidBST(root)
|
||||
def __init__(self):
|
||||
self.maxVal = float('-inf') # 因为后台测试数据中有int最小值
|
||||
|
||||
def isValidBST(self, root):
|
||||
if root is None:
|
||||
return True
|
||||
|
||||
left = self.isValidBST(root.left)
|
||||
# 中序遍历,验证遍历的元素是不是从小到大
|
||||
if self.maxVal < root.val:
|
||||
self.maxVal = root.val
|
||||
else:
|
||||
return False
|
||||
right = self.isValidBST(root.right)
|
||||
|
||||
return left and right
|
||||
|
||||
```
|
||||
递归法(版本三)直接取该树的最小值
|
||||
```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 isValidBST(self, root: TreeNode) -> bool:
|
||||
def __init__(self):
|
||||
self.pre = None # 用来记录前一个节点
|
||||
|
||||
def isValidBST(self, root):
|
||||
if root is None:
|
||||
return True
|
||||
|
||||
left = self.isValidBST(root.left)
|
||||
|
||||
if self.pre is not None and self.pre.val >= root.val:
|
||||
return False
|
||||
self.pre = root # 记录前一个节点
|
||||
|
||||
right = self.isValidBST(root.right)
|
||||
return left and right
|
||||
|
||||
|
||||
|
||||
```
|
||||
迭代法
|
||||
```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 isValidBST(self, root):
|
||||
stack = []
|
||||
cur = root
|
||||
pre = None
|
||||
while cur or stack:
|
||||
if cur: # 指针来访问节点,访问到最底层
|
||||
pre = None # 记录前一个节点
|
||||
while cur is not None or len(stack) > 0:
|
||||
if cur is not None:
|
||||
stack.append(cur)
|
||||
cur = cur.left
|
||||
else: # 逐一处理节点
|
||||
cur = stack.pop()
|
||||
if pre and cur.val <= pre.val: # 比较当前节点和前节点的值的大小
|
||||
cur = cur.left # 左
|
||||
else:
|
||||
cur = stack.pop() # 中
|
||||
if pre is not None and cur.val <= pre.val:
|
||||
return False
|
||||
pre = cur
|
||||
cur = cur.right
|
||||
pre = cur # 保存前一个访问的结点
|
||||
cur = cur.right # 右
|
||||
return True
|
||||
|
||||
```
|
||||
```python
|
||||
# 遵循Carl的写法,只添加了节点判断的部分
|
||||
class Solution:
|
||||
def isValidBST(self, root: TreeNode) -> bool:
|
||||
# method 2
|
||||
que, pre = [], None
|
||||
while root or que:
|
||||
while root:
|
||||
que.append(root)
|
||||
root = root.left
|
||||
root = que.pop()
|
||||
# 对第一个节点只做记录,对后面的节点进行比较
|
||||
if pre is None:
|
||||
pre = root.val
|
||||
else:
|
||||
if pre >= root.val: return False
|
||||
pre = root.val
|
||||
root = root.right
|
||||
return True
|
||||
```
|
||||
|
||||
|
||||
## Go
|
||||
|
||||
|
|
|
|||
|
|
@ -400,8 +400,6 @@ public:
|
|||
};
|
||||
```
|
||||
|
||||
## Python
|
||||
|
||||
|
||||
# 105.从前序与中序遍历序列构造二叉树
|
||||
|
||||
|
|
@ -692,38 +690,6 @@ class Solution {
|
|||
|
||||
## Python
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
|
||||
# 第一步: 特殊情况讨论: 树为空. 或者说是递归终止条件
|
||||
if not postorder:
|
||||
return
|
||||
|
||||
# 第二步: 后序遍历的最后一个就是当前的中间节点
|
||||
root_val = postorder[-1]
|
||||
root = TreeNode(root_val)
|
||||
|
||||
# 第三步: 找切割点.
|
||||
root_index = inorder.index(root_val)
|
||||
|
||||
# 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
|
||||
left_inorder = inorder[:root_index]
|
||||
right_inorder = inorder[root_index + 1:]
|
||||
|
||||
# 第五步: 切割postorder数组. 得到postorder数组的左,右半边.
|
||||
# ⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的.
|
||||
left_postorder = postorder[:len(left_inorder)]
|
||||
right_postorder = postorder[len(left_inorder): len(postorder) - 1]
|
||||
|
||||
|
||||
# 第六步: 递归
|
||||
root.left = self.buildTree(left_inorder, left_postorder)
|
||||
root.right = self.buildTree(right_inorder, right_postorder)
|
||||
|
||||
# 第七步: 返回答案
|
||||
return root
|
||||
```
|
||||
|
||||
105.从前序与中序遍历序列构造二叉树
|
||||
|
||||
```python
|
||||
|
|
@ -752,7 +718,7 @@ class Solution:
|
|||
# 第六步: 递归
|
||||
root.left = self.buildTree(preorder_left, inorder_left)
|
||||
root.right = self.buildTree(preorder_right, inorder_right)
|
||||
|
||||
# 第七步: 返回答案
|
||||
return root
|
||||
```
|
||||
|
||||
|
|
@ -784,7 +750,7 @@ class Solution:
|
|||
# 第六步: 递归
|
||||
root.left = self.buildTree(inorder_left, postorder_left)
|
||||
root.right = self.buildTree(inorder_right, postorder_right)
|
||||
|
||||
# 第七步: 返回答案
|
||||
return root
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -316,73 +316,65 @@ 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
|
||||
class Solution:
|
||||
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
|
||||
'''
|
||||
构造二叉树:重点是选取数组最中间元素为分割点,左侧是递归左区间;右侧是递归右区间
|
||||
必然是平衡树
|
||||
左闭右闭区间
|
||||
'''
|
||||
# 返回根节点
|
||||
root = self.traversal(nums, 0, len(nums)-1)
|
||||
return root
|
||||
|
||||
def traversal(self, nums: List[int], left: int, right: int) -> TreeNode:
|
||||
# Base Case
|
||||
if left > right:
|
||||
return None
|
||||
|
||||
# 确定左右界的中心,防越界
|
||||
mid = left + (right - left) // 2
|
||||
# 构建根节点
|
||||
mid_root = TreeNode(nums[mid])
|
||||
# 构建以左右界的中心为分割点的左右子树
|
||||
mid_root.left = self.traversal(nums, left, mid-1)
|
||||
mid_root.right = self.traversal(nums, mid+1, right)
|
||||
root = TreeNode(nums[mid])
|
||||
root.left = self.traversal(nums, left, mid - 1)
|
||||
root.right = self.traversal(nums, mid + 1, right)
|
||||
return root
|
||||
|
||||
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
|
||||
root = self.traversal(nums, 0, len(nums) - 1)
|
||||
return root
|
||||
|
||||
# 返回由被传入的左右界定义的某子树的根节点
|
||||
return mid_root
|
||||
```
|
||||
|
||||
**迭代**(左闭右开)
|
||||
迭代法
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
class Solution:
|
||||
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
|
||||
if len(nums) == 0: return None
|
||||
root = TreeNode() # 初始化
|
||||
nodeSt = [root]
|
||||
leftSt = [0]
|
||||
rightSt = [len(nums)]
|
||||
|
||||
while nodeSt:
|
||||
node = nodeSt.pop() # 处理根节点
|
||||
left = leftSt.pop()
|
||||
right = rightSt.pop()
|
||||
mid = left + (right - left) // 2
|
||||
node.val = nums[mid]
|
||||
|
||||
if left < mid: # 处理左区间
|
||||
node.left = TreeNode()
|
||||
nodeSt.append(node.left)
|
||||
leftSt.append(left)
|
||||
rightSt.append(mid)
|
||||
|
||||
if right > mid + 1: # 处理右区间
|
||||
node.right = TreeNode()
|
||||
nodeSt.append(node.right)
|
||||
leftSt.append(mid + 1)
|
||||
rightSt.append(right)
|
||||
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
|
||||
if len(nums) == 0:
|
||||
return None
|
||||
|
||||
root = TreeNode(0) # 初始根节点
|
||||
nodeQue = deque() # 放遍历的节点
|
||||
leftQue = deque() # 保存左区间下标
|
||||
rightQue = deque() # 保存右区间下标
|
||||
|
||||
nodeQue.append(root) # 根节点入队列
|
||||
leftQue.append(0) # 0为左区间下标初始位置
|
||||
rightQue.append(len(nums) - 1) # len(nums) - 1为右区间下标初始位置
|
||||
|
||||
while nodeQue:
|
||||
curNode = nodeQue.popleft()
|
||||
left = leftQue.popleft()
|
||||
right = rightQue.popleft()
|
||||
mid = left + (right - left) // 2
|
||||
|
||||
curNode.val = nums[mid] # 将mid对应的元素给中间节点
|
||||
|
||||
if left <= mid - 1: # 处理左区间
|
||||
curNode.left = TreeNode(0)
|
||||
nodeQue.append(curNode.left)
|
||||
leftQue.append(left)
|
||||
rightQue.append(mid - 1)
|
||||
|
||||
if right >= mid + 1: # 处理右区间
|
||||
curNode.right = TreeNode(0)
|
||||
nodeQue.append(curNode.right)
|
||||
leftQue.append(mid + 1)
|
||||
rightQue.append(right)
|
||||
|
||||
return root
|
||||
|
||||
```
|
||||
|
||||
## Go
|
||||
|
|
|
|||
|
|
@ -536,23 +536,67 @@ class Solution:
|
|||
|
||||
```python
|
||||
class Solution:
|
||||
def isBalanced(self, root: TreeNode) -> bool:
|
||||
return self.height(root) != -1
|
||||
def height(self, node: TreeNode) -> int:
|
||||
if not node:
|
||||
return 0
|
||||
left = self.height(node.left)
|
||||
if left == -1:
|
||||
return -1
|
||||
right = self.height(node.right)
|
||||
if right == -1 or abs(left - right) > 1:
|
||||
return -1
|
||||
return max(left, right) + 1
|
||||
def isBalanced(self, root: Optional[TreeNode]) -> bool:
|
||||
return self.get_hight(root) != -1
|
||||
def get_hight(self, node):
|
||||
if not node:
|
||||
return 0
|
||||
left = self.get_hight(node.left)
|
||||
right = self.get_hight(node.right)
|
||||
if left == -1 or right == -1 or abs(left - right) > 1:
|
||||
return -1
|
||||
return max(left, right) + 1
|
||||
```
|
||||
|
||||
|
||||
迭代法:
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def getDepth(self, cur):
|
||||
st = []
|
||||
if cur is not None:
|
||||
st.append(cur)
|
||||
depth = 0
|
||||
result = 0
|
||||
while st:
|
||||
node = st[-1]
|
||||
if node is not None:
|
||||
st.pop()
|
||||
st.append(node) # 中
|
||||
st.append(None)
|
||||
depth += 1
|
||||
if node.right:
|
||||
st.append(node.right) # 右
|
||||
if node.left:
|
||||
st.append(node.left) # 左
|
||||
|
||||
else:
|
||||
node = st.pop()
|
||||
st.pop()
|
||||
depth -= 1
|
||||
result = max(result, depth)
|
||||
return result
|
||||
|
||||
def isBalanced(self, root):
|
||||
st = []
|
||||
if root is None:
|
||||
return True
|
||||
st.append(root)
|
||||
while st:
|
||||
node = st.pop() # 中
|
||||
if abs(self.getDepth(node.left) - self.getDepth(node.right)) > 1:
|
||||
return False
|
||||
if node.right:
|
||||
st.append(node.right) # 右(空节点不入栈)
|
||||
if node.left:
|
||||
st.append(node.left) # 左(空节点不入栈)
|
||||
return True
|
||||
|
||||
```
|
||||
|
||||
迭代法精简版:
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def isBalanced(self, root: Optional[TreeNode]) -> bool:
|
||||
|
|
@ -576,8 +620,6 @@ class Solution:
|
|||
height_map[real_node] = 1 + max(left, right)
|
||||
return True
|
||||
```
|
||||
|
||||
|
||||
### Go
|
||||
|
||||
```Go
|
||||
|
|
|
|||
|
|
@ -302,36 +302,72 @@ 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
|
||||
class Solution:
|
||||
def minDepth(self, root: TreeNode) -> int:
|
||||
if not root:
|
||||
def getDepth(self, node):
|
||||
if node is None:
|
||||
return 0
|
||||
leftDepth = self.getDepth(node.left) # 左
|
||||
rightDepth = self.getDepth(node.right) # 右
|
||||
|
||||
if not root.left and not root.right:
|
||||
return 1
|
||||
# 当一个左子树为空,右不为空,这时并不是最低点
|
||||
if node.left is None and node.right is not None:
|
||||
return 1 + rightDepth
|
||||
|
||||
left_depth = float('inf')
|
||||
right_depth = float('inf')
|
||||
# 当一个右子树为空,左不为空,这时并不是最低点
|
||||
if node.left is not None and node.right is None:
|
||||
return 1 + leftDepth
|
||||
|
||||
if root.left:
|
||||
left_depth = self.minDepth(root.left)
|
||||
if root.right:
|
||||
right_depth = self.minDepth(root.right)
|
||||
|
||||
return 1 + min(left_depth, right_depth)
|
||||
result = 1 + min(leftDepth, rightDepth)
|
||||
return result
|
||||
|
||||
def minDepth(self, root):
|
||||
return self.getDepth(root)
|
||||
|
||||
```
|
||||
递归法(版本二)
|
||||
|
||||
迭代法:
|
||||
```python
|
||||
class Solution:
|
||||
def minDepth(self, root):
|
||||
if root is None:
|
||||
return 0
|
||||
if root.left is None and root.right is not None:
|
||||
return 1 + self.minDepth(root.right)
|
||||
if root.left is not None and root.right is None:
|
||||
return 1 + self.minDepth(root.left)
|
||||
return 1 + min(self.minDepth(root.left), self.minDepth(root.right))
|
||||
|
||||
|
||||
```
|
||||
递归法(版本三)前序
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.result = float('inf')
|
||||
|
||||
def getDepth(self, node, depth):
|
||||
if node is None:
|
||||
return
|
||||
if node.left is None and node.right is None:
|
||||
self.result = min(self.result, depth)
|
||||
if node.left:
|
||||
self.getDepth(node.left, depth + 1)
|
||||
if node.right:
|
||||
self.getDepth(node.right, depth + 1)
|
||||
|
||||
def minDepth(self, root):
|
||||
if root is None:
|
||||
return 0
|
||||
self.getDepth(root, 1)
|
||||
return self.result
|
||||
|
||||
|
||||
```
|
||||
迭代法
|
||||
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
|
|
@ -364,39 +400,7 @@ class Solution:
|
|||
return depth
|
||||
```
|
||||
|
||||
迭代法:
|
||||
|
||||
```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 minDepth(self, root: TreeNode) -> int:
|
||||
if not root:
|
||||
return 0
|
||||
|
||||
queue = collections.deque([(root, 1)])
|
||||
|
||||
while queue:
|
||||
node, depth = queue.popleft()
|
||||
|
||||
# Check if the node is a leaf node
|
||||
if not node.left and not node.right:
|
||||
return depth
|
||||
|
||||
# Add left and right child to the queue
|
||||
if node.left:
|
||||
queue.append((node.left, depth+1))
|
||||
if node.right:
|
||||
queue.append((node.right, depth+1))
|
||||
|
||||
return 0
|
||||
|
||||
```
|
||||
|
||||
## Go
|
||||
|
||||
|
|
|
|||
|
|
@ -242,9 +242,9 @@ class Solution {
|
|||
|
||||
for (int i = 1; i < len; i++) {
|
||||
dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
|
||||
dp[i][2] = Math.max(dp[i - 1][2], dp[i][1] + prices[i]);
|
||||
dp[i][3] = Math.max(dp[i - 1][3], dp[i][2] - prices[i]);
|
||||
dp[i][4] = Math.max(dp[i - 1][4], dp[i][3] + prices[i]);
|
||||
dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
|
||||
dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
|
||||
dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
|
||||
}
|
||||
|
||||
return dp[len - 1][4];
|
||||
|
|
|
|||
|
|
@ -352,12 +352,9 @@ class Solution {
|
|||
```
|
||||
|
||||
## Python
|
||||
**回溯+正反序判断回文串**
|
||||
回溯 基本版
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.paths = []
|
||||
self.path = []
|
||||
|
||||
def partition(self, s: str) -> List[List[str]]:
|
||||
'''
|
||||
|
|
@ -366,52 +363,14 @@ class Solution:
|
|||
当切割线迭代至字符串末尾,说明找到一种方法
|
||||
类似组合问题,为了不重复切割同一位置,需要start_index来做标记下一轮递归的起始位置(切割线)
|
||||
'''
|
||||
self.path.clear()
|
||||
self.paths.clear()
|
||||
self.backtracking(s, 0)
|
||||
return self.paths
|
||||
result = []
|
||||
self.backtracking(s, 0, [], result)
|
||||
return result
|
||||
|
||||
def backtracking(self, s: str, start_index: int) -> None:
|
||||
def backtracking(self, s, start_index, path, result ):
|
||||
# Base Case
|
||||
if start_index >= len(s):
|
||||
self.paths.append(self.path[:])
|
||||
return
|
||||
|
||||
# 单层递归逻辑
|
||||
for i in range(start_index, len(s)):
|
||||
# 此次比其他组合题目多了一步判断:
|
||||
# 判断被截取的这一段子串([start_index, i])是否为回文串
|
||||
temp = s[start_index:i+1]
|
||||
if temp == temp[::-1]: # 若反序和正序相同,意味着这是回文串
|
||||
self.path.append(temp)
|
||||
self.backtracking(s, i+1) # 递归纵向遍历:从下一处进行切割,判断其余是否仍为回文串
|
||||
self.path.pop()
|
||||
else:
|
||||
continue
|
||||
```
|
||||
**回溯+函数判断回文串**
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.paths = []
|
||||
self.path = []
|
||||
|
||||
def partition(self, s: str) -> List[List[str]]:
|
||||
'''
|
||||
递归用于纵向遍历
|
||||
for循环用于横向遍历
|
||||
当切割线迭代至字符串末尾,说明找到一种方法
|
||||
类似组合问题,为了不重复切割同一位置,需要start_index来做标记下一轮递归的起始位置(切割线)
|
||||
'''
|
||||
self.path.clear()
|
||||
self.paths.clear()
|
||||
self.backtracking(s, 0)
|
||||
return self.paths
|
||||
|
||||
def backtracking(self, s: str, start_index: int) -> None:
|
||||
# Base Case
|
||||
if start_index >= len(s):
|
||||
self.paths.append(self.path[:])
|
||||
if start_index == len(s):
|
||||
result.append(path[:])
|
||||
return
|
||||
|
||||
# 单层递归逻辑
|
||||
|
|
@ -419,11 +378,10 @@ class Solution:
|
|||
# 此次比其他组合题目多了一步判断:
|
||||
# 判断被截取的这一段子串([start_index, i])是否为回文串
|
||||
if self.is_palindrome(s, start_index, i):
|
||||
self.path.append(s[start_index:i+1])
|
||||
self.backtracking(s, i+1) # 递归纵向遍历:从下一处进行切割,判断其余是否仍为回文串
|
||||
self.path.pop() # 回溯
|
||||
else:
|
||||
continue
|
||||
path.append(s[start_index:i+1])
|
||||
self.backtracking(s, i+1, path, result) # 递归纵向遍历:从下一处进行切割,判断其余是否仍为回文串
|
||||
path.pop() # 回溯
|
||||
|
||||
|
||||
def is_palindrome(self, s: str, start: int, end: int) -> bool:
|
||||
i: int = start
|
||||
|
|
@ -433,9 +391,88 @@ class Solution:
|
|||
return False
|
||||
i += 1
|
||||
j -= 1
|
||||
return True
|
||||
return True
|
||||
```
|
||||
回溯+优化判定回文函数
|
||||
```python
|
||||
class Solution:
|
||||
|
||||
def partition(self, s: str) -> List[List[str]]:
|
||||
result = []
|
||||
self.backtracking(s, 0, [], result)
|
||||
return result
|
||||
|
||||
def backtracking(self, s, start_index, path, result ):
|
||||
# Base Case
|
||||
if start_index == len(s):
|
||||
result.append(path[:])
|
||||
return
|
||||
|
||||
# 单层递归逻辑
|
||||
for i in range(start_index, len(s)):
|
||||
# 若反序和正序相同,意味着这是回文串
|
||||
if s[start_index: i + 1] == s[start_index: i + 1][::-1]:
|
||||
path.append(s[start_index:i+1])
|
||||
self.backtracking(s, i+1, path, result) # 递归纵向遍历:从下一处进行切割,判断其余是否仍为回文串
|
||||
path.pop() # 回溯
|
||||
|
||||
```
|
||||
回溯+高效判断回文子串
|
||||
```python
|
||||
class Solution:
|
||||
def partition(self, s: str) -> List[List[str]]:
|
||||
result = []
|
||||
isPalindrome = [[False] * len(s) for _ in range(len(s))] # 初始化isPalindrome矩阵
|
||||
self.computePalindrome(s, isPalindrome)
|
||||
self.backtracking(s, 0, [], result, isPalindrome)
|
||||
return result
|
||||
|
||||
def backtracking(self, s, startIndex, path, result, isPalindrome):
|
||||
if startIndex >= len(s):
|
||||
result.append(path[:])
|
||||
return
|
||||
|
||||
for i in range(startIndex, len(s)):
|
||||
if isPalindrome[startIndex][i]: # 是回文子串
|
||||
substring = s[startIndex:i + 1]
|
||||
path.append(substring)
|
||||
self.backtracking(s, i + 1, path, result, isPalindrome) # 寻找i+1为起始位置的子串
|
||||
path.pop() # 回溯过程,弹出本次已经填在的子串
|
||||
|
||||
def computePalindrome(self, s, isPalindrome):
|
||||
for i in range(len(s) - 1, -1, -1): # 需要倒序计算,保证在i行时,i+1行已经计算好了
|
||||
for j in range(i, len(s)):
|
||||
if j == i:
|
||||
isPalindrome[i][j] = True
|
||||
elif j - i == 1:
|
||||
isPalindrome[i][j] = (s[i] == s[j])
|
||||
else:
|
||||
isPalindrome[i][j] = (s[i] == s[j] and isPalindrome[i+1][j-1])
|
||||
```
|
||||
回溯+使用all函数判断回文子串
|
||||
```python
|
||||
class Solution:
|
||||
def partition(self, s: str) -> List[List[str]]:
|
||||
result = []
|
||||
self.partition_helper(s, 0, [], result)
|
||||
return result
|
||||
|
||||
def partition_helper(self, s, start_index, path, result):
|
||||
if start_index == len(s):
|
||||
result.append(path[:])
|
||||
return
|
||||
|
||||
for i in range(start_index + 1, len(s) + 1):
|
||||
sub = s[start_index:i]
|
||||
if self.isPalindrome(sub):
|
||||
path.append(sub)
|
||||
self.partition_helper(s, i, path, result)
|
||||
path.pop()
|
||||
|
||||
def isPalindrome(self, s):
|
||||
return all(s[i] == s[len(s) - 1 - i] for i in range(len(s) // 2))
|
||||
|
||||
```
|
||||
## Go
|
||||
```go
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -249,44 +249,74 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python
|
||||
暴力法
|
||||
```python
|
||||
# 解法1
|
||||
class Solution:
|
||||
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
|
||||
n = len(gas)
|
||||
cur_sum = 0
|
||||
min_sum = float('inf')
|
||||
|
||||
for i in range(n):
|
||||
cur_sum += gas[i] - cost[i]
|
||||
min_sum = min(min_sum, cur_sum)
|
||||
|
||||
if cur_sum < 0: return -1
|
||||
if min_sum >= 0: return 0
|
||||
|
||||
for j in range(n - 1, 0, -1):
|
||||
min_sum += gas[j] - cost[j]
|
||||
if min_sum >= 0:
|
||||
return j
|
||||
|
||||
return -1
|
||||
```
|
||||
|
||||
```python
|
||||
# 解法2
|
||||
class Solution:
|
||||
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
|
||||
start = 0
|
||||
curSum = 0
|
||||
totalSum = 0
|
||||
for i in range(len(cost)):
|
||||
rest = gas[i] - cost[i] # 记录剩余油量
|
||||
index = (i + 1) % len(cost) # 下一个加油站的索引
|
||||
|
||||
while rest > 0 and index != i: # 模拟以i为起点行驶一圈(如果有rest==0,那么答案就不唯一了)
|
||||
rest += gas[index] - cost[index] # 更新剩余油量
|
||||
index = (index + 1) % len(cost) # 更新下一个加油站的索引
|
||||
|
||||
if rest >= 0 and index == i: # 如果以i为起点跑一圈,剩余油量>=0,并且回到起始位置
|
||||
return i # 返回起始位置i
|
||||
|
||||
return -1 # 所有起始位置都无法环绕一圈,返回-1
|
||||
|
||||
```
|
||||
贪心(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
|
||||
curSum = 0 # 当前累计的剩余油量
|
||||
minFuel = float('inf') # 从起点出发,油箱里的油量最小值
|
||||
|
||||
for i in range(len(gas)):
|
||||
rest = gas[i] - cost[i]
|
||||
curSum += rest
|
||||
if curSum < minFuel:
|
||||
minFuel = curSum
|
||||
|
||||
if curSum < 0:
|
||||
return -1 # 情况1:整个行程的总消耗大于总供给,无法完成一圈
|
||||
|
||||
if minFuel >= 0:
|
||||
return 0 # 情况2:从起点出发到任何一个加油站时油箱的剩余油量都不会小于0,可以从起点出发完成一圈
|
||||
|
||||
for i in range(len(gas) - 1, -1, -1):
|
||||
rest = gas[i] - cost[i]
|
||||
minFuel += rest
|
||||
if minFuel >= 0:
|
||||
return i # 情况3:找到一个位置使得从该位置出发油箱的剩余油量不会小于0,返回该位置的索引
|
||||
|
||||
return -1 # 无法完成一圈
|
||||
|
||||
```
|
||||
贪心(版本二)
|
||||
```python
|
||||
class Solution:
|
||||
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
|
||||
curSum = 0 # 当前累计的剩余油量
|
||||
totalSum = 0 # 总剩余油量
|
||||
start = 0 # 起始位置
|
||||
|
||||
for i in range(len(gas)):
|
||||
curSum += gas[i] - cost[i]
|
||||
totalSum += gas[i] - cost[i]
|
||||
if curSum < 0:
|
||||
curSum = 0
|
||||
start = i + 1
|
||||
if totalSum < 0: return -1
|
||||
|
||||
if curSum < 0: # 当前累计剩余油量curSum小于0
|
||||
start = i + 1 # 起始位置更新为i+1
|
||||
curSum = 0 # curSum重新从0开始累计
|
||||
|
||||
if totalSum < 0:
|
||||
return -1 # 总剩余油量totalSum小于0,说明无法环绕一圈
|
||||
return start
|
||||
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -178,13 +178,21 @@ class Solution {
|
|||
class Solution:
|
||||
def candy(self, ratings: List[int]) -> int:
|
||||
candyVec = [1] * len(ratings)
|
||||
|
||||
# 从前向后遍历,处理右侧比左侧评分高的情况
|
||||
for i in range(1, len(ratings)):
|
||||
if ratings[i] > ratings[i - 1]:
|
||||
candyVec[i] = candyVec[i - 1] + 1
|
||||
for j in range(len(ratings) - 2, -1, -1):
|
||||
if ratings[j] > ratings[j + 1]:
|
||||
candyVec[j] = max(candyVec[j], candyVec[j + 1] + 1)
|
||||
return sum(candyVec)
|
||||
|
||||
# 从后向前遍历,处理左侧比右侧评分高的情况
|
||||
for i in range(len(ratings) - 2, -1, -1):
|
||||
if ratings[i] > ratings[i + 1]:
|
||||
candyVec[i] = max(candyVec[i], candyVec[i + 1] + 1)
|
||||
|
||||
# 统计结果
|
||||
result = sum(candyVec)
|
||||
return result
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -337,10 +337,53 @@ class Solution {
|
|||
|
||||
Python:
|
||||
|
||||
回溯
|
||||
```python
|
||||
class Solution:
|
||||
def backtracking(self, s: str, wordSet: set[str], startIndex: int) -> bool:
|
||||
# 边界情况:已经遍历到字符串末尾,返回True
|
||||
if startIndex >= len(s):
|
||||
return True
|
||||
|
||||
# 遍历所有可能的拆分位置
|
||||
for i in range(startIndex, len(s)):
|
||||
word = s[startIndex:i + 1] # 截取子串
|
||||
if word in wordSet and self.backtracking(s, wordSet, i + 1):
|
||||
# 如果截取的子串在字典中,并且后续部分也可以被拆分成单词,返回True
|
||||
return True
|
||||
|
||||
# 无法进行有效拆分,返回False
|
||||
return False
|
||||
|
||||
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
|
||||
wordSet = set(wordDict) # 转换为哈希集合,提高查找效率
|
||||
return self.backtracking(s, wordSet, 0)
|
||||
|
||||
```
|
||||
DP(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
|
||||
wordSet = set(wordDict)
|
||||
n = len(s)
|
||||
dp = [False] * (n + 1) # dp[i] 表示字符串的前 i 个字符是否可以被拆分成单词
|
||||
dp[0] = True # 初始状态,空字符串可以被拆分成单词
|
||||
|
||||
for i in range(1, n + 1): # 遍历背包
|
||||
for j in range(i): # 遍历单词
|
||||
if dp[j] and s[j:i] in wordSet:
|
||||
dp[i] = True # 如果 s[0:j] 可以被拆分成单词,并且 s[j:i] 在单词集合中存在,则 s[0:i] 可以被拆分成单词
|
||||
break
|
||||
|
||||
return dp[n]
|
||||
|
||||
|
||||
```
|
||||
DP(版本二)
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
|
||||
'''排列'''
|
||||
dp = [False]*(len(s) + 1)
|
||||
dp[0] = True
|
||||
# 遍历背包
|
||||
|
|
@ -351,17 +394,6 @@ class Solution:
|
|||
dp[j] = dp[j] or (dp[j - len(word)] and word == s[j - len(word):j])
|
||||
return dp[len(s)]
|
||||
```
|
||||
```python
|
||||
class Solution: # 和视频中写法一致(和最上面C++写法一致)
|
||||
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
|
||||
dp = [False]*(len(s)+1)
|
||||
dp[0]=True
|
||||
for j in range(1,len(s)+1):
|
||||
for i in range(j):
|
||||
word = s[i:j]
|
||||
if word in wordDict and dp[i]: dp[j]=True
|
||||
return dp[-1]
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -437,6 +437,34 @@ object Solution {
|
|||
}
|
||||
```
|
||||
|
||||
C#:
|
||||
```CSharp
|
||||
public class Solution
|
||||
{
|
||||
public ListNode DetectCycle(ListNode head)
|
||||
{
|
||||
ListNode fast = head;
|
||||
ListNode slow = head;
|
||||
while (fast != null && fast.next != null)
|
||||
{
|
||||
slow = slow.next;
|
||||
fast = fast.next.next;
|
||||
if (fast == slow)
|
||||
{
|
||||
fast = head;
|
||||
while (fast != slow)
|
||||
{
|
||||
fast = fast.next;
|
||||
slow = slow.next;
|
||||
}
|
||||
return fast;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
|
|
|||
|
|
@ -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<len;i++){
|
||||
|
||||
result[2] = Math.max(result[0]+nums[i],result[1]);
|
||||
|
||||
result[0] = result[1];
|
||||
result[1] = result[2];
|
||||
}
|
||||
|
||||
return result[2];
|
||||
}
|
||||
}
|
||||
|
||||
// 进一步对滚动数组的空间优化 dp数组只存与计算相关的两次数据
|
||||
class Solution {
|
||||
public int rob(int[] nums) {
|
||||
if (nums.length == 1) {
|
||||
|
|
@ -151,11 +180,11 @@ class Solution {
|
|||
// 优化空间 dp数组只用2格空间 只记录与当前计算相关的前两个结果
|
||||
int[] dp = new int[2];
|
||||
dp[0] = nums[0];
|
||||
dp[1] = nums[0] > nums[1] ? nums[0] : nums[1];
|
||||
dp[1] = Math.max(nums[0],nums[1]);
|
||||
int res = 0;
|
||||
// 遍历
|
||||
for (int i = 2; i < nums.length; i++) {
|
||||
res = (dp[0] + nums[i]) > dp[1] ? (dp[0] + nums[i]) : dp[1];
|
||||
res = Math.max((dp[0] + nums[i]) , dp[1] );
|
||||
dp[0] = dp[1];
|
||||
dp[1] = res;
|
||||
}
|
||||
|
|
@ -166,30 +195,65 @@ class Solution {
|
|||
```
|
||||
|
||||
Python:
|
||||
|
||||
1维DP
|
||||
```python
|
||||
class Solution:
|
||||
def rob(self, nums: List[int]) -> int:
|
||||
if len(nums) == 0:
|
||||
if len(nums) == 0: # 如果没有房屋,返回0
|
||||
return 0
|
||||
if len(nums) == 1:
|
||||
if len(nums) == 1: # 如果只有一个房屋,返回其金额
|
||||
return nums[0]
|
||||
|
||||
# 创建一个动态规划数组,用于存储最大金额
|
||||
dp = [0] * len(nums)
|
||||
dp[0] = nums[0]
|
||||
dp[1] = max(nums[0], nums[1])
|
||||
dp[0] = nums[0] # 将dp的第一个元素设置为第一个房屋的金额
|
||||
dp[1] = max(nums[0], nums[1]) # 将dp的第二个元素设置为第一二个房屋中的金额较大者
|
||||
|
||||
# 遍历剩余的房屋
|
||||
for i in range(2, len(nums)):
|
||||
dp[i] = max(dp[i-2]+nums[i], dp[i-1])
|
||||
return dp[-1]
|
||||
# 对于每个房屋,选择抢劫当前房屋和抢劫前一个房屋的最大金额
|
||||
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
|
||||
|
||||
return dp[-1] # 返回最后一个房屋中可抢劫的最大金额
|
||||
```
|
||||
2维DP
|
||||
```python
|
||||
class Solution: # 二维dp数组写法
|
||||
class Solution:
|
||||
def rob(self, nums: List[int]) -> int:
|
||||
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][1],dp[i-1][0])
|
||||
dp[i][1] = dp[i-1][0]+nums[i]
|
||||
print(dp)
|
||||
return max(dp[-1])
|
||||
if not nums: # 如果没有房屋,返回0
|
||||
return 0
|
||||
|
||||
n = len(nums)
|
||||
dp = [[0, 0] for _ in range(n)] # 创建二维动态规划数组,dp[i][0]表示不抢劫第i个房屋的最大金额,dp[i][1]表示抢劫第i个房屋的最大金额
|
||||
|
||||
dp[0][1] = nums[0] # 抢劫第一个房屋的最大金额为第一个房屋的金额
|
||||
|
||||
for i in range(1, n):
|
||||
dp[i][0] = max(dp[i-1][0], dp[i-1][1]) # 不抢劫第i个房屋,最大金额为前一个房屋抢劫和不抢劫的最大值
|
||||
dp[i][1] = dp[i-1][0] + nums[i] # 抢劫第i个房屋,最大金额为前一个房屋不抢劫的最大金额加上当前房屋的金额
|
||||
|
||||
return max(dp[n-1][0], dp[n-1][1]) # 返回最后一个房屋中可抢劫的最大金额
|
||||
|
||||
```
|
||||
优化版
|
||||
```python
|
||||
class Solution:
|
||||
def rob(self, nums: List[int]) -> int:
|
||||
if not nums: # 如果没有房屋,返回0
|
||||
return 0
|
||||
|
||||
prev_max = 0 # 上一个房屋的最大金额
|
||||
curr_max = 0 # 当前房屋的最大金额
|
||||
|
||||
for num in nums:
|
||||
temp = curr_max # 临时变量保存当前房屋的最大金额
|
||||
curr_max = max(prev_max + num, curr_max) # 更新当前房屋的最大金额
|
||||
prev_max = temp # 更新上一个房屋的最大金额
|
||||
|
||||
return curr_max # 返回最后一个房屋中可抢劫的最大金额
|
||||
|
||||
|
||||
```
|
||||
Go:
|
||||
```Go
|
||||
|
|
|
|||
|
|
@ -596,6 +596,41 @@ class Solution {
|
|||
}
|
||||
```
|
||||
|
||||
C#
|
||||
```CSharp
|
||||
/**
|
||||
* Definition for singly-linked list.
|
||||
* public class ListNode {
|
||||
* public int val;
|
||||
* public ListNode next;
|
||||
* public ListNode(int val=0, ListNode next=null) {
|
||||
* this.val = val;
|
||||
* this.next = next;
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public class Solution
|
||||
{
|
||||
public ListNode RemoveElements(ListNode head, int val)
|
||||
{
|
||||
ListNode dummyHead = new ListNode(0,head);
|
||||
ListNode temp = dummyHead;
|
||||
while(temp.next != null)
|
||||
{
|
||||
if(temp.next.val == val)
|
||||
{
|
||||
temp.next = temp.next.next;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = temp.next;
|
||||
}
|
||||
}
|
||||
return dummyHead.next;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ class MyStack {
|
|||
|
||||
```
|
||||
优化,使用一个 Queue 实现,但用卡哥的逻辑实现
|
||||
```
|
||||
```Java
|
||||
class MyStack {
|
||||
Queue<Integer> queue;
|
||||
|
||||
|
|
|
|||
|
|
@ -991,6 +991,53 @@ impl Solution {
|
|||
}
|
||||
```
|
||||
|
||||
### C#
|
||||
|
||||
```csharp
|
||||
//递归
|
||||
public class Solution {
|
||||
public TreeNode InvertTree(TreeNode root) {
|
||||
if (root == null) return root;
|
||||
|
||||
swap(root);
|
||||
InvertTree(root.left);
|
||||
InvertTree(root.right);
|
||||
return root;
|
||||
}
|
||||
|
||||
public void swap(TreeNode node) {
|
||||
TreeNode temp = node.left;
|
||||
node.left = node.right;
|
||||
node.right = temp;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
//迭代
|
||||
public class Solution {
|
||||
public TreeNode InvertTree(TreeNode root) {
|
||||
if (root == null) return null;
|
||||
Stack<TreeNode> stack=new Stack<TreeNode>();
|
||||
stack.Push(root);
|
||||
while(stack.Count>0)
|
||||
{
|
||||
TreeNode node = stack.Pop();
|
||||
swap(node);
|
||||
if(node.right!=null) stack.Push(node.right);
|
||||
if(node.left!=null) stack.Push(node.left);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
public void swap(TreeNode node) {
|
||||
TreeNode temp = node.left;
|
||||
node.left = node.right;
|
||||
node.right = temp;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
递归法:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// 版本一,先遍历物品, 再遍历背包
|
||||
|
|
|
|||
|
|
@ -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]:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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]<nums[i-1]:
|
||||
# nums[i] 为波谷,1. 前面是波峰,up+1,2. 前面是波谷,down不变,取较大值
|
||||
down = max(down, up+1)
|
||||
return max(up, down)
|
||||
def wiggleMaxLength(self, nums):
|
||||
dp = [[0, 0] for _ in range(len(nums))] # 创建二维dp数组,用于记录摆动序列的最大长度
|
||||
dp[0][0] = dp[0][1] = 1 # 初始条件,序列中的第一个元素默认为峰值,最小长度为1
|
||||
for i in range(1, len(nums)):
|
||||
dp[i][0] = dp[i][1] = 1 # 初始化当前位置的dp值为1
|
||||
for j in range(i):
|
||||
if nums[j] > nums[i]:
|
||||
dp[i][1] = max(dp[i][1], dp[j][0] + 1) # 如果前一个数比当前数大,可以形成一个上升峰值,更新dp[i][1]
|
||||
for j in range(i):
|
||||
if nums[j] < nums[i]:
|
||||
dp[i][0] = max(dp[i][0], dp[j][1] + 1) # 如果前一个数比当前数小,可以形成一个下降峰值,更新dp[i][0]
|
||||
return max(dp[-1][0], dp[-1][1]) # 返回最大的摆动序列长度
|
||||
|
||||
```
|
||||
|
||||
动态规划(版本三)优化
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def wiggleMaxLength(self, nums):
|
||||
if len(nums) <= 1:
|
||||
return len(nums) # 如果数组长度为0或1,则返回数组长度
|
||||
|
||||
up = down = 1 # 记录上升和下降摆动序列的最大长度
|
||||
for i in range(1, len(nums)):
|
||||
if nums[i] > nums[i-1]:
|
||||
up = down + 1 # 如果当前数比前一个数大,则可以形成一个上升峰值
|
||||
elif nums[i] < nums[i-1]:
|
||||
down = up + 1 # 如果当前数比前一个数小,则可以形成一个下降峰值
|
||||
|
||||
return max(up, down) # 返回上升和下降摆动序列的最大长度
|
||||
|
||||
|
||||
```
|
||||
### Go
|
||||
|
||||
**贪心**
|
||||
|
|
|
|||
|
|
@ -176,21 +176,37 @@ class Solution {
|
|||
|
||||
Python:
|
||||
|
||||
|
||||
卡哥版
|
||||
```python
|
||||
class Solution:
|
||||
def combinationSum4(self, nums, target):
|
||||
def combinationSum4(self, nums: List[int], target: int) -> int:
|
||||
dp = [0] * (target + 1)
|
||||
dp[0] = 1
|
||||
for i in range(1, target + 1): # 遍历背包
|
||||
for j in range(len(nums)): # 遍历物品
|
||||
if i - nums[j] >= 0:
|
||||
dp[i] += dp[i - nums[j]]
|
||||
return dp[target]
|
||||
|
||||
for i in range(1, target+1):
|
||||
for j in nums:
|
||||
if i >= j:
|
||||
dp[i] += dp[i - j]
|
||||
|
||||
return dp[-1]
|
||||
```
|
||||
优化版
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def combinationSum4(self, nums: List[int], target: int) -> int:
|
||||
dp = [0] * (target + 1) # 创建动态规划数组,用于存储组合总数
|
||||
dp[0] = 1 # 初始化背包容量为0时的组合总数为1
|
||||
|
||||
for i in range(1, target + 1): # 遍历背包容量
|
||||
for j in nums: # 遍历物品列表
|
||||
if i >= j: # 当背包容量大于等于当前物品重量时
|
||||
dp[i] += dp[i - j] # 更新组合总数
|
||||
|
||||
return dp[-1] # 返回背包容量为target时的组合总数
|
||||
|
||||
|
||||
```
|
||||
Go:
|
||||
```go
|
||||
func combinationSum4(nums []int, target int) int {
|
||||
|
|
|
|||
|
|
@ -247,8 +247,7 @@ class Solution {
|
|||
|
||||
|
||||
### Python
|
||||
|
||||
**递归后序遍历**
|
||||
递归
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
|
|
@ -257,47 +256,64 @@ class Solution {
|
|||
# self.left = left
|
||||
# self.right = right
|
||||
class Solution:
|
||||
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
|
||||
if not root:
|
||||
def sumOfLeftLeaves(self, root):
|
||||
if root is None:
|
||||
return 0
|
||||
if root.left is None and root.right is None:
|
||||
return 0
|
||||
|
||||
# 检查根节点的左子节点是否为叶节点
|
||||
if root.left and not root.left.left and not root.left.right:
|
||||
left_val = root.left.val
|
||||
else:
|
||||
left_val = self.sumOfLeftLeaves(root.left)
|
||||
leftValue = self.sumOfLeftLeaves(root.left) # 左
|
||||
if root.left and not root.left.left and not root.left.right: # 左子树是左叶子的情况
|
||||
leftValue = root.left.val
|
||||
|
||||
# 递归地计算右子树左叶节点的和
|
||||
right_val = self.sumOfLeftLeaves(root.right)
|
||||
|
||||
return left_val + right_val
|
||||
rightValue = self.sumOfLeftLeaves(root.right) # 右
|
||||
|
||||
sum_val = leftValue + rightValue # 中
|
||||
return sum_val
|
||||
```
|
||||
递归精简版
|
||||
|
||||
```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 sumOfLeftLeaves(self, root):
|
||||
if root is None:
|
||||
return 0
|
||||
leftValue = 0
|
||||
if root.left is not None and root.left.left is None and root.left.right is None:
|
||||
leftValue = root.left.val
|
||||
return leftValue + self.sumOfLeftLeaves(root.left) + self.sumOfLeftLeaves(root.right)
|
||||
```
|
||||
|
||||
**迭代**
|
||||
迭代法
|
||||
```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 sumOfLeftLeaves(self, root: TreeNode) -> int:
|
||||
"""
|
||||
Idea: Each time check current node's left node.
|
||||
If current node don't have one, skip it.
|
||||
"""
|
||||
stack = []
|
||||
if root:
|
||||
stack.append(root)
|
||||
res = 0
|
||||
|
||||
while stack:
|
||||
# 每次都把当前节点的左节点加进去.
|
||||
cur_node = stack.pop()
|
||||
if cur_node.left and not cur_node.left.left and not cur_node.left.right:
|
||||
res += cur_node.left.val
|
||||
|
||||
if cur_node.left:
|
||||
stack.append(cur_node.left)
|
||||
if cur_node.right:
|
||||
stack.append(cur_node.right)
|
||||
|
||||
return res
|
||||
def sumOfLeftLeaves(self, root):
|
||||
if root is None:
|
||||
return 0
|
||||
st = [root]
|
||||
result = 0
|
||||
while st:
|
||||
node = st.pop()
|
||||
if node.left and node.left.left is None and node.left.right is None:
|
||||
result += node.left.val
|
||||
if node.right:
|
||||
st.append(node.right)
|
||||
if node.left:
|
||||
st.append(node.left)
|
||||
return result
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -191,14 +191,14 @@ class Solution {
|
|||
public int[][] reconstructQueue(int[][] people) {
|
||||
// 身高从大到小排(身高相同k小的站前面)
|
||||
Arrays.sort(people, (a, b) -> {
|
||||
if (a[0] == b[0]) return a[1] - b[1];
|
||||
return b[0] - a[0];
|
||||
if (a[0] == b[0]) return a[1] - b[1]; // a - b 是升序排列,故在a[0] == b[0]的狀況下,會根據k值升序排列
|
||||
return b[0] - a[0]; //b - a 是降序排列,在a[0] != b[0],的狀況會根據h值降序排列
|
||||
});
|
||||
|
||||
LinkedList<int[]> que = new LinkedList<>();
|
||||
|
||||
for (int[] p : people) {
|
||||
que.add(p[1],p);
|
||||
que.add(p[1],p); //Linkedlist.add(index, value),會將value插入到指定index裡。
|
||||
}
|
||||
|
||||
return que.toArray(new int[people.length][]);
|
||||
|
|
@ -295,19 +295,19 @@ var reconstructQueue = function(people) {
|
|||
|
||||
```Rust
|
||||
impl Solution {
|
||||
pub fn reconstruct_queue(people: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
|
||||
let mut people = people;
|
||||
pub fn reconstruct_queue(mut people: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
|
||||
let mut queue = vec![];
|
||||
people.sort_by(|a, b| {
|
||||
if a[0] == b[0] { return a[1].cmp(&b[1]); }
|
||||
if a[0] == b[0] {
|
||||
return a[1].cmp(&b[1]);
|
||||
}
|
||||
b[0].cmp(&a[0])
|
||||
});
|
||||
let mut que: Vec<Vec<i32>> = Vec::new();
|
||||
que.push(people[0].clone());
|
||||
for i in 1..people.len() {
|
||||
let position = people[i][1];
|
||||
que.insert(position as usize, people[i].clone());
|
||||
queue.push(people[0].clone());
|
||||
for v in people.iter().skip(1) {
|
||||
queue.insert(v[1] as usize, v.clone());
|
||||
}
|
||||
que
|
||||
queue
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -218,8 +218,12 @@ class Solution {
|
|||
for(int i = 0; i < n; i++) {
|
||||
for(int j = target; j >= nums[i]; j--) {
|
||||
//物品 i 的重量是 nums[i],其价值也是 nums[i]
|
||||
dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i]);
|
||||
dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
|
||||
}
|
||||
|
||||
//剪枝一下,每一次完成內層的for-loop,立即檢查是否dp[target] == target,優化時間複雜度(26ms -> 20ms)
|
||||
if(dp[target] == target)
|
||||
return true;
|
||||
}
|
||||
return dp[target] == target;
|
||||
}
|
||||
|
|
@ -294,64 +298,142 @@ false true false false false true true false false false false false
|
|||
false true false false false true true false false false false true
|
||||
false true false false false true true false false false true true
|
||||
```
|
||||
二維數組整數版本
|
||||
```Java
|
||||
class Solution {
|
||||
public boolean canPartition(int[] nums) {
|
||||
//using 2-D DP array.
|
||||
int len = nums.length;
|
||||
//check edge cases;
|
||||
if(len == 0)
|
||||
return false;
|
||||
|
||||
### Python:
|
||||
```python
|
||||
# 一维度数组解法
|
||||
class Solution:
|
||||
def canPartition(self, nums: List[int]) -> bool:
|
||||
target = sum(nums)
|
||||
if target % 2 == 1: return False
|
||||
target //= 2
|
||||
dp = [0] * (target + 1)
|
||||
for i in range(len(nums)):
|
||||
for j in range(target, nums[i] - 1, -1):
|
||||
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])
|
||||
return target == dp[target]
|
||||
int sum = 0;
|
||||
for (int num : nums)
|
||||
sum += num;
|
||||
//we only deal with even numbers. If sum is odd, return false;
|
||||
if(sum % 2 == 1)
|
||||
return false;
|
||||
|
||||
int target = sum / 2;
|
||||
int[][] dp = new int[nums.length][target + 1];
|
||||
|
||||
// for(int j = 0; j <= target; j++){
|
||||
// if(j < nums[0])
|
||||
// dp[0][j] = 0;
|
||||
// else
|
||||
// dp[0][j] = nums[0];
|
||||
// }
|
||||
|
||||
//initialize dp array
|
||||
for(int j = nums[0]; j <= target; j++){
|
||||
dp[0][j] = nums[0];
|
||||
}
|
||||
|
||||
for(int i = 1; i < len; i++){
|
||||
for(int j = 0; j <= target; j++){
|
||||
if (j < nums[i])
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
else
|
||||
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//print out DP array
|
||||
// for(int x : dp){
|
||||
// System.out.print(x + ",");
|
||||
// }
|
||||
// System.out.print(" "+i+" row"+"\n");
|
||||
return dp[len - 1][target] == target;
|
||||
}
|
||||
}
|
||||
//dp数组的打印结果 for test case 1.
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 1, 1, 1, 1, 5, 6, 6, 6, 6, 6, 6,
|
||||
0, 1, 1, 1, 1, 5, 6, 6, 6, 6, 6, 11,
|
||||
0, 1, 1, 1, 1, 5, 6, 6, 6, 6, 10, 11,
|
||||
```
|
||||
|
||||
### Python:
|
||||
卡哥版
|
||||
```python
|
||||
# 二维度数组解法
|
||||
class Solution:
|
||||
def canPartition(self, nums: List[int]) -> bool:
|
||||
target = sum(nums)
|
||||
nums = sorted(nums)
|
||||
_sum = 0
|
||||
|
||||
# 做最初的判断
|
||||
if target % 2 != 0:
|
||||
# dp[i]中的i表示背包内总和
|
||||
# 题目中说:每个数组中的元素不会超过 100,数组的大小不会超过 200
|
||||
# 总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了
|
||||
dp = [0] * 10001
|
||||
for num in nums:
|
||||
_sum += num
|
||||
# 也可以使用内置函数一步求和
|
||||
# _sum = sum(nums)
|
||||
if _sum % 2 == 1:
|
||||
return False
|
||||
target = _sum // 2
|
||||
|
||||
# 开始 0-1背包
|
||||
for num in nums:
|
||||
for j in range(target, num - 1, -1): # 每一个元素一定是不可重复放入,所以从大到小遍历
|
||||
dp[j] = max(dp[j], dp[j - num] + num)
|
||||
|
||||
# 集合中的元素正好可以凑成总和target
|
||||
if dp[target] == target:
|
||||
return True
|
||||
return False
|
||||
|
||||
```
|
||||
二维DP版
|
||||
```python
|
||||
class Solution:
|
||||
def canPartition(self, nums: List[int]) -> bool:
|
||||
|
||||
total_sum = sum(nums)
|
||||
|
||||
if total_sum % 2 != 0:
|
||||
return False
|
||||
|
||||
# 找到 target value 可以认为这个是背包的体积
|
||||
target = target // 2
|
||||
target_sum = total_sum // 2
|
||||
dp = [[False] * (target_sum + 1) for _ in range(len(nums) + 1)]
|
||||
|
||||
row = len(nums)
|
||||
col = target + 1
|
||||
# 初始化第一行(空子集可以得到和为0)
|
||||
for i in range(len(nums) + 1):
|
||||
dp[i][0] = True
|
||||
|
||||
# 定义 dp table
|
||||
dp = [[0 for _ in range(col)] for _ in range(row)]
|
||||
|
||||
# 初始 dp value
|
||||
for i in range(row):
|
||||
dp[i][0] = 0
|
||||
|
||||
for j in range(1, target):
|
||||
if nums[0] <= j:
|
||||
dp[0][j] = nums[0]
|
||||
|
||||
# 遍历 先遍历物品再遍历背包
|
||||
for i in range(1, row):
|
||||
|
||||
cur_weight = nums[i]
|
||||
cur_value = nums[i]
|
||||
|
||||
for j in range(1, col):
|
||||
if cur_weight > j:
|
||||
for i in range(1, len(nums) + 1):
|
||||
for j in range(1, target_sum + 1):
|
||||
if j < nums[i - 1]:
|
||||
# 当前数字大于目标和时,无法使用该数字
|
||||
dp[i][j] = dp[i - 1][j]
|
||||
else:
|
||||
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - cur_weight] + cur_value)
|
||||
|
||||
# 输出结果
|
||||
return dp[-1][col - 1] == target
|
||||
# 当前数字小于等于目标和时,可以选择使用或不使用该数字
|
||||
dp[i][j] = dp[i - 1][j] or dp[i - 1][j - nums[i - 1]]
|
||||
|
||||
return dp[len(nums)][target_sum]
|
||||
|
||||
```
|
||||
一维DP版
|
||||
```python
|
||||
class Solution:
|
||||
def canPartition(self, nums: List[int]) -> bool:
|
||||
|
||||
total_sum = sum(nums)
|
||||
|
||||
if total_sum % 2 != 0:
|
||||
return False
|
||||
|
||||
target_sum = total_sum // 2
|
||||
dp = [False] * (target_sum + 1)
|
||||
dp[0] = True
|
||||
|
||||
for num in nums:
|
||||
# 从target_sum逆序迭代到num,步长为-1
|
||||
for i in range(target_sum, num - 1, -1):
|
||||
dp[i] = dp[i] or dp[i - num]
|
||||
return dp[target_sum]
|
||||
|
||||
|
||||
```
|
||||
|
||||
### Go:
|
||||
|
|
|
|||
|
|
@ -248,20 +248,45 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python
|
||||
贪心 基于左边界
|
||||
```python
|
||||
class Solution:
|
||||
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
|
||||
if len(intervals) == 0: return 0
|
||||
intervals.sort(key=lambda x: x[1])
|
||||
count = 1 # 记录非交叉区间的个数
|
||||
end = intervals[0][1] # 记录区间分割点
|
||||
if not intervals:
|
||||
return 0
|
||||
|
||||
intervals.sort(key=lambda x: x[0]) # 按照左边界升序排序
|
||||
count = 0 # 记录重叠区间数量
|
||||
|
||||
for i in range(1, len(intervals)):
|
||||
if end <= intervals[i][0]:
|
||||
if intervals[i][0] < intervals[i - 1][1]: # 存在重叠区间
|
||||
intervals[i][1] = min(intervals[i - 1][1], intervals[i][1]) # 更新重叠区间的右边界
|
||||
count += 1
|
||||
end = intervals[i][1]
|
||||
return len(intervals) - count
|
||||
```
|
||||
|
||||
return count
|
||||
|
||||
```
|
||||
贪心 基于左边界 把452.用最少数量的箭引爆气球代码稍做修改
|
||||
```python
|
||||
class Solution:
|
||||
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
|
||||
if not intervals:
|
||||
return 0
|
||||
|
||||
intervals.sort(key=lambda x: x[0]) # 按照左边界升序排序
|
||||
|
||||
result = 1 # 不重叠区间数量,初始化为1,因为至少有一个不重叠的区间
|
||||
|
||||
for i in range(1, len(intervals)):
|
||||
if intervals[i][0] >= intervals[i - 1][1]: # 没有重叠
|
||||
result += 1
|
||||
else: # 重叠情况
|
||||
intervals[i][1] = min(intervals[i - 1][1], intervals[i][1]) # 更新重叠区间的右边界
|
||||
|
||||
return len(intervals) - result
|
||||
|
||||
|
||||
```
|
||||
### Go
|
||||
```go
|
||||
func eraseOverlapIntervals(intervals [][]int) int {
|
||||
|
|
|
|||
|
|
@ -324,88 +324,90 @@ class Solution {
|
|||
```
|
||||
|
||||
## Python
|
||||
|
||||
递归法(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
|
||||
if not root : return None # 节点为空,返回
|
||||
if root.val < key :
|
||||
root.right = self.deleteNode(root.right, key)
|
||||
elif root.val > key :
|
||||
def deleteNode(self, root, key):
|
||||
if root is None:
|
||||
return root
|
||||
if root.val == key:
|
||||
if root.left is None and root.right is None:
|
||||
return None
|
||||
elif root.left is None:
|
||||
return root.right
|
||||
elif root.right is None:
|
||||
return root.left
|
||||
else:
|
||||
cur = root.right
|
||||
while cur.left is not None:
|
||||
cur = cur.left
|
||||
cur.left = root.left
|
||||
return root.right
|
||||
if root.val > key:
|
||||
root.left = self.deleteNode(root.left, key)
|
||||
else:
|
||||
# 当前节点的左子树为空,返回当前的右子树
|
||||
if not root.left : return root.right
|
||||
# 当前节点的右子树为空,返回当前的左子树
|
||||
if not root.right: return root.left
|
||||
# 左右子树都不为空,找到右孩子的最左节点 记为p
|
||||
node = root.right
|
||||
while node.left :
|
||||
node = node.left
|
||||
# 将当前节点的左子树挂在p的左孩子上
|
||||
node.left = root.left
|
||||
# 当前节点的右子树替换掉当前节点,完成当前节点的删除
|
||||
root = root.right
|
||||
if root.val < key:
|
||||
root.right = self.deleteNode(root.right, key)
|
||||
return root
|
||||
```
|
||||
|
||||
**普通二叉树的删除方式**
|
||||
递归法(版本二)
|
||||
```python
|
||||
class Solution:
|
||||
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
|
||||
if not root: return root
|
||||
if root.val == key:
|
||||
if not root.right: # 这里第二次操作目标值:最终删除的作用
|
||||
def deleteNode(self, root, key):
|
||||
if root is None: # 如果根节点为空,直接返回
|
||||
return root
|
||||
if root.val == key: # 找到要删除的节点
|
||||
if root.right is None: # 如果右子树为空,直接返回左子树作为新的根节点
|
||||
return root.left
|
||||
tmp = root.right
|
||||
while tmp.left:
|
||||
tmp = tmp.left
|
||||
root.val, tmp.val = tmp.val, root.val # 这里第一次操作目标值:交换目标值其右子树最左面节点。
|
||||
|
||||
root.left = self.deleteNode(root.left, key)
|
||||
root.right = self.deleteNode(root.right, key)
|
||||
cur = root.right
|
||||
while cur.left: # 找到右子树中的最左节点
|
||||
cur = cur.left
|
||||
root.val, cur.val = cur.val, root.val # 将要删除的节点值与最左节点值交换
|
||||
root.left = self.deleteNode(root.left, key) # 在左子树中递归删除目标节点
|
||||
root.right = self.deleteNode(root.right, key) # 在右子树中递归删除目标节点
|
||||
return root
|
||||
|
||||
```
|
||||
|
||||
**迭代法**
|
||||
```python
|
||||
class Solution:
|
||||
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
|
||||
# 找到节点后分两步,1. 把节点的左子树和右子树连起来,2. 把右子树跟父节点连起来
|
||||
# root is None
|
||||
if not root: return root
|
||||
p = root
|
||||
last = None
|
||||
while p:
|
||||
if p.val==key:
|
||||
# 1. connect left to right
|
||||
# right is not None -> left is None | left is not None
|
||||
if p.right:
|
||||
if p.left:
|
||||
node = p.right
|
||||
while node.left:
|
||||
node = node.left
|
||||
node.left = p.left
|
||||
right = p.right
|
||||
else:
|
||||
# right is None -> right=left
|
||||
right = p.left
|
||||
# 2. connect right to last
|
||||
if last==None:
|
||||
root = right
|
||||
elif last.val>key:
|
||||
last.left = right
|
||||
else:
|
||||
last.right = right
|
||||
# 3. return
|
||||
def deleteOneNode(self, target: TreeNode) -> TreeNode:
|
||||
"""
|
||||
将目标节点(删除节点)的左子树放到目标节点的右子树的最左面节点的左孩子位置上
|
||||
并返回目标节点右孩子为新的根节点
|
||||
是动画里模拟的过程
|
||||
"""
|
||||
if target is None:
|
||||
return target
|
||||
if target.right is None:
|
||||
return target.left
|
||||
cur = target.right
|
||||
while cur.left:
|
||||
cur = cur.left
|
||||
cur.left = target.left
|
||||
return target.right
|
||||
|
||||
def deleteNode(self, root: TreeNode, key: int) -> TreeNode:
|
||||
if root is None:
|
||||
return root
|
||||
cur = root
|
||||
pre = None # 记录cur的父节点,用来删除cur
|
||||
while cur:
|
||||
if cur.val == key:
|
||||
break
|
||||
pre = cur
|
||||
if cur.val > key:
|
||||
cur = cur.left
|
||||
else:
|
||||
# Update last and continue
|
||||
last = p
|
||||
if p.val>key:
|
||||
p = p.left
|
||||
else:
|
||||
p = p.right
|
||||
cur = cur.right
|
||||
if pre is None: # 如果搜索树只有头结点
|
||||
return self.deleteOneNode(cur)
|
||||
# pre 要知道是删左孩子还是右孩子
|
||||
if pre.left and pre.left.val == key:
|
||||
pre.left = self.deleteOneNode(cur)
|
||||
if pre.right and pre.right.val == key:
|
||||
pre.right = self.deleteOneNode(cur)
|
||||
return root
|
||||
```
|
||||
|
||||
|
|
@ -680,6 +682,40 @@ object Solution {
|
|||
}
|
||||
```
|
||||
|
||||
## rust
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn delete_node(
|
||||
root: Option<Rc<RefCell<TreeNode>>>,
|
||||
key: i32,
|
||||
) -> Option<Rc<RefCell<TreeNode>>> {
|
||||
root.as_ref()?;
|
||||
|
||||
let mut node = root.as_ref().unwrap().borrow_mut();
|
||||
match node.val.cmp(&key) {
|
||||
std::cmp::Ordering::Less => node.right = Self::delete_node(node.right.clone(), key),
|
||||
std::cmp::Ordering::Equal => match (node.left.clone(), node.right.clone()) {
|
||||
(None, None) => return None,
|
||||
(None, Some(r)) => return Some(r),
|
||||
(Some(l), None) => return Some(l),
|
||||
(Some(l), Some(r)) => {
|
||||
let mut cur = Some(r.clone());
|
||||
while let Some(n) = cur.clone().unwrap().borrow().left.clone() {
|
||||
cur = Some(n);
|
||||
}
|
||||
cur.unwrap().borrow_mut().left = Some(l);
|
||||
return Some(r);
|
||||
}
|
||||
},
|
||||
std::cmp::Ordering::Greater => node.left = Self::delete_node(node.left.clone(), key),
|
||||
}
|
||||
drop(node);
|
||||
root
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
|
|
|||
|
|
@ -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 <len(g) and s[i] >= g[res]: #小饼干先喂饱小胃口
|
||||
res += 1
|
||||
return res
|
||||
def findContentChildren(self, g, s):
|
||||
g.sort() # 将孩子的贪心因子排序
|
||||
s.sort() # 将饼干的尺寸排序
|
||||
index = len(s) - 1 # 饼干数组的下标,从最后一个饼干开始
|
||||
result = 0 # 满足孩子的数量
|
||||
for i in range(len(g)-1, -1, -1): # 遍历胃口,从最后一个孩子开始
|
||||
if index >= 0 and s[index] >= g[i]: # 遍历饼干
|
||||
result += 1
|
||||
index -= 1
|
||||
return result
|
||||
|
||||
```
|
||||
|
||||
贪心 小饼干优先
|
||||
```python
|
||||
class Solution:
|
||||
# 思路2:优先考虑大胃口
|
||||
def findContentChildren(self, g: List[int], s: List[int]) -> int:
|
||||
g.sort()
|
||||
s.sort()
|
||||
start, count = len(s) - 1, 0
|
||||
for index in range(len(g) - 1, -1, -1): # 先喂饱大胃口
|
||||
if start >= 0 and g[index] <= s[start]:
|
||||
start -= 1
|
||||
count += 1
|
||||
return count
|
||||
def findContentChildren(self, g, s):
|
||||
g.sort() # 将孩子的贪心因子排序
|
||||
s.sort() # 将饼干的尺寸排序
|
||||
index = 0
|
||||
for i in range(len(s)): # 遍历饼干
|
||||
if index < len(g) and g[index] <= s[i]: # 如果当前孩子的贪心因子小于等于当前饼干尺寸
|
||||
index += 1 # 满足一个孩子,指向下一个孩子
|
||||
return index # 返回满足的孩子数目
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -210,19 +210,35 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python
|
||||
DP(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
|
||||
dp = [[0] * (n + 1) for _ in range(m + 1)] # 默认初始化0
|
||||
dp = [[0] * (n + 1) for _ in range(m + 1)] # 创建二维动态规划数组,初始化为0
|
||||
for s in strs: # 遍历物品
|
||||
zeroNum = s.count('0') # 统计0的个数
|
||||
oneNum = len(s) - zeroNum # 统计1的个数
|
||||
for i in range(m, zeroNum - 1, -1): # 遍历背包容量且从后向前遍历
|
||||
for j in range(n, oneNum - 1, -1):
|
||||
dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1) # 状态转移方程
|
||||
return dp[m][n]
|
||||
|
||||
```
|
||||
DP(版本二)
|
||||
```python
|
||||
class Solution:
|
||||
def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
|
||||
dp = [[0] * (n + 1) for _ in range(m + 1)] # 创建二维动态规划数组,初始化为0
|
||||
# 遍历物品
|
||||
for str in strs:
|
||||
ones = str.count('1')
|
||||
zeros = str.count('0')
|
||||
# 遍历背包容量且从后向前遍历!
|
||||
for s in strs:
|
||||
ones = s.count('1') # 统计字符串中1的个数
|
||||
zeros = s.count('0') # 统计字符串中0的个数
|
||||
# 遍历背包容量且从后向前遍历
|
||||
for i in range(m, zeros - 1, -1):
|
||||
for j in range(n, ones - 1, -1):
|
||||
dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1)
|
||||
dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1) # 状态转移方程
|
||||
return dp[m][n]
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -268,80 +268,56 @@ class Solution {
|
|||
|
||||
### Python
|
||||
|
||||
python3
|
||||
**回溯**
|
||||
|
||||
回溯 利用set去重
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.paths = []
|
||||
self.path = []
|
||||
|
||||
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
|
||||
'''
|
||||
本题求自增子序列,所以不能改变原数组顺序
|
||||
'''
|
||||
self.backtracking(nums, 0)
|
||||
return self.paths
|
||||
|
||||
def backtracking(self, nums: List[int], start_index: int):
|
||||
# 收集结果,同78.子集,仍要置于终止条件之前
|
||||
if len(self.path) >= 2:
|
||||
# 本题要求所有的节点
|
||||
self.paths.append(self.path[:])
|
||||
def findSubsequences(self, nums):
|
||||
result = []
|
||||
path = []
|
||||
self.backtracking(nums, 0, path, result)
|
||||
return result
|
||||
|
||||
def backtracking(self, nums, startIndex, path, result):
|
||||
if len(path) > 1:
|
||||
result.append(path[:]) # 注意要使用切片将当前路径的副本加入结果集
|
||||
# 注意这里不要加return,要取树上的节点
|
||||
|
||||
# Base Case(可忽略)
|
||||
if start_index == len(nums):
|
||||
return
|
||||
|
||||
# 单层递归逻辑
|
||||
# 深度遍历中每一层都会有一个全新的usage_list用于记录本层元素是否重复使用
|
||||
usage_list = set()
|
||||
# 同层横向遍历
|
||||
for i in range(start_index, len(nums)):
|
||||
# 若当前元素值小于前一个时(非递增)或者曾用过,跳入下一循环
|
||||
if (self.path and nums[i] < self.path[-1]) or nums[i] in usage_list:
|
||||
uset = set() # 使用集合对本层元素进行去重
|
||||
for i in range(startIndex, len(nums)):
|
||||
if (path and nums[i] < path[-1]) or nums[i] in uset:
|
||||
continue
|
||||
usage_list.add(nums[i])
|
||||
self.path.append(nums[i])
|
||||
self.backtracking(nums, i+1)
|
||||
self.path.pop()
|
||||
|
||||
uset.add(nums[i]) # 记录这个元素在本层用过了,本层后面不能再用了
|
||||
path.append(nums[i])
|
||||
self.backtracking(nums, i + 1, path, result)
|
||||
path.pop()
|
||||
|
||||
```
|
||||
**回溯+哈希表去重**
|
||||
回溯 利用哈希表去重
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.paths = []
|
||||
self.path = []
|
||||
def findSubsequences(self, nums):
|
||||
result = []
|
||||
path = []
|
||||
self.backtracking(nums, 0, path, result)
|
||||
return result
|
||||
|
||||
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
|
||||
'''
|
||||
本题求自增子序列,所以不能改变原数组顺序
|
||||
'''
|
||||
self.backtracking(nums, 0)
|
||||
return self.paths
|
||||
|
||||
def backtracking(self, nums: List[int], start_index: int):
|
||||
# 收集结果,同78.子集,仍要置于终止条件之前
|
||||
if len(self.path) >= 2:
|
||||
# 本题要求所有的节点
|
||||
self.paths.append(self.path[:])
|
||||
def backtracking(self, nums, startIndex, path, result):
|
||||
if len(path) > 1:
|
||||
result.append(path[:]) # 注意要使用切片将当前路径的副本加入结果集
|
||||
|
||||
# Base Case(可忽略)
|
||||
if start_index == len(nums):
|
||||
return
|
||||
used = [0] * 201 # 使用数组来进行去重操作,题目说数值范围[-100, 100]
|
||||
for i in range(startIndex, len(nums)):
|
||||
if (path and nums[i] < path[-1]) or used[nums[i] + 100] == 1:
|
||||
continue # 如果当前元素小于上一个元素,或者已经使用过当前元素,则跳过当前元素
|
||||
|
||||
used[nums[i] + 100] = 1 # 标记当前元素已经使用过
|
||||
path.append(nums[i]) # 将当前元素加入当前递增子序列
|
||||
self.backtracking(nums, i + 1, path, result)
|
||||
path.pop()
|
||||
|
||||
|
||||
# 单层递归逻辑
|
||||
# 深度遍历中每一层都会有一个全新的usage_list用于记录本层元素是否重复使用
|
||||
usage_list = [False] * 201 # 使用列表去重,题中取值范围[-100, 100]
|
||||
# 同层横向遍历
|
||||
for i in range(start_index, len(nums)):
|
||||
# 若当前元素值小于前一个时(非递增)或者曾用过,跳入下一循环
|
||||
if (self.path and nums[i] < self.path[-1]) or usage_list[nums[i]+100] == True:
|
||||
continue
|
||||
usage_list[nums[i]+100] = True
|
||||
self.path.append(nums[i])
|
||||
self.backtracking(nums, i+1)
|
||||
self.path.pop()
|
||||
```
|
||||
### Go
|
||||
|
||||
|
|
|
|||
|
|
@ -293,19 +293,84 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python
|
||||
回溯版
|
||||
```python
|
||||
class Solution:
|
||||
|
||||
|
||||
def backtracking(self, candidates, target, total, startIndex, path, result):
|
||||
if total == target:
|
||||
result.append(path[:]) # 将当前路径的副本添加到结果中
|
||||
# 如果 sum + candidates[i] > target,则停止遍历
|
||||
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 + 1, path, result)
|
||||
total -= candidates[i]
|
||||
path.pop()
|
||||
|
||||
def findTargetSumWays(self, nums: List[int], target: int) -> int:
|
||||
total = sum(nums)
|
||||
if target > total:
|
||||
return 0 # 此时没有方案
|
||||
if (target + total) % 2 != 0:
|
||||
return 0 # 此时没有方案,两个整数相加时要注意数值溢出的问题
|
||||
bagSize = (target + total) // 2 # 转化为组合总和问题,bagSize就是目标和
|
||||
|
||||
# 以下是回溯法代码
|
||||
result = []
|
||||
nums.sort() # 需要对nums进行排序
|
||||
self.backtracking(nums, bagSize, 0, 0, [], result)
|
||||
return len(result)
|
||||
|
||||
```
|
||||
二维DP
|
||||
```python
|
||||
class Solution:
|
||||
def findTargetSumWays(self, nums: List[int], target: int) -> int:
|
||||
sumValue = sum(nums)
|
||||
#注意边界条件为 target>sumValue or target<-sumValue or (sumValue + target) % 2 == 1
|
||||
if abs(target) > sumValue or (sumValue + target) % 2 == 1: return 0
|
||||
bagSize = (sumValue + target) // 2
|
||||
dp = [0] * (bagSize + 1)
|
||||
dp[0] = 1
|
||||
for i in range(len(nums)):
|
||||
for j in range(bagSize, nums[i] - 1, -1):
|
||||
dp[j] += dp[j - nums[i]]
|
||||
return dp[bagSize]
|
||||
total_sum = sum(nums) # 计算nums的总和
|
||||
if abs(target) > total_sum:
|
||||
return 0 # 此时没有方案
|
||||
if (target + total_sum) % 2 == 1:
|
||||
return 0 # 此时没有方案
|
||||
target_sum = (target + total_sum) // 2 # 目标和
|
||||
|
||||
# 创建二维动态规划数组,行表示选取的元素数量,列表示累加和
|
||||
dp = [[0] * (target_sum + 1) for _ in range(len(nums) + 1)]
|
||||
|
||||
# 初始化状态
|
||||
dp[0][0] = 1
|
||||
|
||||
# 动态规划过程
|
||||
for i in range(1, len(nums) + 1):
|
||||
for j in range(target_sum + 1):
|
||||
dp[i][j] = dp[i - 1][j] # 不选取当前元素
|
||||
if j >= nums[i - 1]:
|
||||
dp[i][j] += dp[i - 1][j - nums[i - 1]] # 选取当前元素
|
||||
|
||||
return dp[len(nums)][target_sum] # 返回达到目标和的方案数
|
||||
|
||||
|
||||
```
|
||||
一维DP
|
||||
```python
|
||||
class Solution:
|
||||
def findTargetSumWays(self, nums: List[int], target: int) -> int:
|
||||
total_sum = sum(nums) # 计算nums的总和
|
||||
if abs(target) > total_sum:
|
||||
return 0 # 此时没有方案
|
||||
if (target + total_sum) % 2 == 1:
|
||||
return 0 # 此时没有方案
|
||||
target_sum = (target + total_sum) // 2 # 目标和
|
||||
dp = [0] * (target_sum + 1) # 创建动态规划数组,初始化为0
|
||||
dp[0] = 1 # 当目标和为0时,只有一种方案,即什么都不选
|
||||
for num in nums:
|
||||
for j in range(target_sum, num - 1, -1):
|
||||
dp[j] += dp[j - num] # 状态转移方程,累加不同选择方式的数量
|
||||
return dp[target_sum] # 返回达到目标和的方案数
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
@ -417,6 +482,31 @@ object Solution {
|
|||
}
|
||||
```
|
||||
|
||||
### Rust
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn find_target_sum_ways(nums: Vec<i32>, target: i32) -> i32 {
|
||||
let sum = nums.iter().sum::<i32>();
|
||||
if target.abs() > sum {
|
||||
return 0;
|
||||
}
|
||||
if (target + sum) % 2 == 1 {
|
||||
return 0;
|
||||
}
|
||||
let size = (sum + target) as usize / 2;
|
||||
let mut dp = vec![0; size + 1];
|
||||
dp[0] = 1;
|
||||
for n in nums {
|
||||
for s in (n as usize..=size).rev() {
|
||||
dp[s] += dp[s - n as usize];
|
||||
}
|
||||
}
|
||||
dp[size]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
|
|
|||
|
|
@ -472,11 +472,63 @@ class Solution {
|
|||
}
|
||||
}
|
||||
```
|
||||
統一迭代法
|
||||
```Java
|
||||
class Solution {
|
||||
public int[] findMode(TreeNode root) {
|
||||
int count = 0;
|
||||
int maxCount = 0;
|
||||
TreeNode pre = null;
|
||||
LinkedList<Integer> res = new LinkedList<>();
|
||||
Stack<TreeNode> stack = new Stack<>();
|
||||
|
||||
if(root != null)
|
||||
stack.add(root);
|
||||
|
||||
while(!stack.isEmpty()){
|
||||
TreeNode curr = stack.peek();
|
||||
if(curr != null){
|
||||
stack.pop();
|
||||
if(curr.right != null)
|
||||
stack.add(curr.right);
|
||||
stack.add(curr);
|
||||
stack.add(null);
|
||||
if(curr.left != null)
|
||||
stack.add(curr.left);
|
||||
}else{
|
||||
stack.pop();
|
||||
TreeNode temp = stack.pop();
|
||||
if(pre == null)
|
||||
count = 1;
|
||||
else if(pre != null && pre.val == temp.val)
|
||||
count++;
|
||||
else
|
||||
count = 1;
|
||||
pre = temp;
|
||||
if(count == maxCount)
|
||||
res.add(temp.val);
|
||||
if(count > maxCount){
|
||||
maxCount = count;
|
||||
res.clear();
|
||||
res.add(temp.val);
|
||||
}
|
||||
}
|
||||
}
|
||||
int[] result = new int[res.size()];
|
||||
int i = 0;
|
||||
for (int x : res){
|
||||
result[i] = x;
|
||||
i++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Python
|
||||
|
||||
> 递归法
|
||||
> 常量空间,递归产生的栈不算
|
||||
递归法(版本一)利用字典
|
||||
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
|
|
@ -485,77 +537,108 @@ class Solution {
|
|||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
from collections import defaultdict
|
||||
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.pre = TreeNode()
|
||||
self.count = 0
|
||||
self.max_count = 0
|
||||
self.result = []
|
||||
def searchBST(self, cur, freq_map):
|
||||
if cur is None:
|
||||
return
|
||||
freq_map[cur.val] += 1 # 统计元素频率
|
||||
self.searchBST(cur.left, freq_map)
|
||||
self.searchBST(cur.right, freq_map)
|
||||
|
||||
def findMode(self, root: TreeNode) -> List[int]:
|
||||
if not root: return None
|
||||
self.search_BST(root)
|
||||
return self.result
|
||||
|
||||
def search_BST(self, cur: TreeNode) -> None:
|
||||
if not cur: return None
|
||||
self.search_BST(cur.left)
|
||||
# 第一个节点
|
||||
if not self.pre:
|
||||
self.count = 1
|
||||
# 与前一个节点数值相同
|
||||
elif self.pre.val == cur.val:
|
||||
self.count += 1
|
||||
# 与前一个节点数值不相同
|
||||
else:
|
||||
self.count = 1
|
||||
self.pre = cur
|
||||
def findMode(self, root):
|
||||
freq_map = defaultdict(int) # key:元素,value:出现频率
|
||||
result = []
|
||||
if root is None:
|
||||
return result
|
||||
self.searchBST(root, freq_map)
|
||||
max_freq = max(freq_map.values())
|
||||
for key, freq in freq_map.items():
|
||||
if freq == max_freq:
|
||||
result.append(key)
|
||||
return result
|
||||
|
||||
if self.count == self.max_count:
|
||||
self.result.append(cur.val)
|
||||
|
||||
if self.count > self.max_count:
|
||||
self.max_count = self.count
|
||||
self.result = [cur.val] # 清空self.result,确保result之前的的元素都失效
|
||||
|
||||
self.search_BST(cur.right)
|
||||
```
|
||||
|
||||
递归法(版本二)利用二叉搜索树性质
|
||||
|
||||
> 迭代法-中序遍历
|
||||
> 利用二叉搜索树特性,在历遍过程中更新结果,一次历遍
|
||||
> 但需要使用额外空间存储历遍的节点
|
||||
```python
|
||||
class Solution:
|
||||
def findMode(self, root: TreeNode) -> List[int]:
|
||||
stack = []
|
||||
def __init__(self):
|
||||
self.maxCount = 0 # 最大频率
|
||||
self.count = 0 # 统计频率
|
||||
self.pre = None
|
||||
self.result = []
|
||||
|
||||
def searchBST(self, cur):
|
||||
if cur is None:
|
||||
return
|
||||
|
||||
self.searchBST(cur.left) # 左
|
||||
# 中
|
||||
if self.pre is None: # 第一个节点
|
||||
self.count = 1
|
||||
elif self.pre.val == cur.val: # 与前一个节点数值相同
|
||||
self.count += 1
|
||||
else: # 与前一个节点数值不同
|
||||
self.count = 1
|
||||
self.pre = cur # 更新上一个节点
|
||||
|
||||
if self.count == self.maxCount: # 如果与最大值频率相同,放进result中
|
||||
self.result.append(cur.val)
|
||||
|
||||
if self.count > self.maxCount: # 如果计数大于最大值频率
|
||||
self.maxCount = self.count # 更新最大频率
|
||||
self.result = [cur.val] # 很关键的一步,不要忘记清空result,之前result里的元素都失效了
|
||||
|
||||
self.searchBST(cur.right) # 右
|
||||
return
|
||||
|
||||
def findMode(self, root):
|
||||
self.count = 0
|
||||
self.maxCount = 0
|
||||
self.pre = None # 记录前一个节点
|
||||
self.result = []
|
||||
|
||||
self.searchBST(root)
|
||||
return self.result
|
||||
```
|
||||
迭代法
|
||||
```python
|
||||
class Solution:
|
||||
def findMode(self, root):
|
||||
st = []
|
||||
cur = root
|
||||
pre = None
|
||||
maxCount, count = 0, 0
|
||||
res = []
|
||||
while cur or stack:
|
||||
if cur: # 指针来访问节点,访问到最底层
|
||||
stack.append(cur)
|
||||
cur = cur.left
|
||||
else: # 逐一处理节点
|
||||
cur = stack.pop()
|
||||
if pre == None: # 第一个节点
|
||||
maxCount = 0 # 最大频率
|
||||
count = 0 # 统计频率
|
||||
result = []
|
||||
|
||||
while cur is not None or st:
|
||||
if cur is not None: # 指针来访问节点,访问到最底层
|
||||
st.append(cur) # 将访问的节点放进栈
|
||||
cur = cur.left # 左
|
||||
else:
|
||||
cur = st.pop()
|
||||
if pre is None: # 第一个节点
|
||||
count = 1
|
||||
elif pre.val == cur.val: # 与前一个节点数值相同
|
||||
count += 1
|
||||
else:
|
||||
else: # 与前一个节点数值不同
|
||||
count = 1
|
||||
if count == maxCount:
|
||||
res.append(cur.val)
|
||||
if count > maxCount:
|
||||
maxCount = count
|
||||
res.clear()
|
||||
res.append(cur.val)
|
||||
|
||||
if count == maxCount: # 如果和最大值相同,放进result中
|
||||
result.append(cur.val)
|
||||
|
||||
if count > maxCount: # 如果计数大于最大值频率
|
||||
maxCount = count # 更新最大频率
|
||||
result = [cur.val] # 很关键的一步,不要忘记清空result,之前result里的元素都失效了
|
||||
|
||||
pre = cur
|
||||
cur = cur.right
|
||||
return res
|
||||
|
||||
cur = cur.right # 右
|
||||
|
||||
return result
|
||||
```
|
||||
## Go
|
||||
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ class Solution {
|
|||
|
||||
Python:
|
||||
```python
|
||||
# 方法 1:
|
||||
class Solution:
|
||||
def nextGreaterElements(self, nums: List[int]) -> List[int]:
|
||||
dp = [-1] * len(nums)
|
||||
|
|
@ -174,6 +175,26 @@ class Solution:
|
|||
stack.pop()
|
||||
stack.append(i%len(nums))
|
||||
return dp
|
||||
|
||||
# 方法 2:
|
||||
class Solution:
|
||||
def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
|
||||
stack = []
|
||||
# 创建答案数组
|
||||
ans = [-1] * len(nums1)
|
||||
for i in range(len(nums2)):
|
||||
while len(stack) > 0 and nums2[i] > nums2[stack[-1]]:
|
||||
# 判断 num1 是否有 nums2[stack[-1]]。如果没有这个判断会出现指针异常
|
||||
if nums2[stack[-1]] in nums1:
|
||||
# 锁定 num1 检索的 index
|
||||
index = nums1.index(nums2[stack[-1]])
|
||||
# 更新答案数组
|
||||
ans[index] = nums2[i]
|
||||
# 弹出小元素
|
||||
# 这个代码一定要放在 if 外面。否则单调栈的逻辑就不成立了
|
||||
stack.pop()
|
||||
stack.append(i)
|
||||
return ans
|
||||
```
|
||||
Go:
|
||||
```go
|
||||
|
|
|
|||
|
|
@ -203,18 +203,9 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python
|
||||
动态规划(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def fib(self, n: int) -> int:
|
||||
if n < 2:
|
||||
return n
|
||||
a, b, c = 0, 1, 0
|
||||
for i in range(1, n):
|
||||
c = a + b
|
||||
a, b = b, c
|
||||
return c
|
||||
|
||||
# 动态规划 (注释版。无修饰)
|
||||
class Solution:
|
||||
def fib(self, n: int) -> int:
|
||||
|
||||
|
|
@ -238,7 +229,48 @@ class Solution:
|
|||
# 返回答案
|
||||
return dp[n]
|
||||
|
||||
# 递归实现
|
||||
```
|
||||
动态规划(版本二)
|
||||
```python
|
||||
|
||||
class Solution:
|
||||
def fib(self, n: int) -> int:
|
||||
if n <= 1:
|
||||
return n
|
||||
|
||||
dp = [0, 1]
|
||||
|
||||
for i in range(2, n + 1):
|
||||
total = dp[0] + dp[1]
|
||||
dp[0] = dp[1]
|
||||
dp[1] = total
|
||||
|
||||
return dp[1]
|
||||
|
||||
|
||||
```
|
||||
动态规划(版本三)
|
||||
```python
|
||||
class Solution:
|
||||
def fib(self, n: int) -> int:
|
||||
if n <= 1:
|
||||
return n
|
||||
|
||||
prev1, prev2 = 0, 1
|
||||
|
||||
for _ in range(2, n + 1):
|
||||
curr = prev1 + prev2
|
||||
prev1, prev2 = prev2, curr
|
||||
|
||||
return prev2
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
递归(版本一)
|
||||
```python
|
||||
|
||||
class Solution:
|
||||
def fib(self, n: int) -> int:
|
||||
if n < 2:
|
||||
|
|
|
|||
|
|
@ -330,19 +330,24 @@ class Solution:
|
|||
# self.right = right
|
||||
from collections import deque
|
||||
class Solution:
|
||||
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
|
||||
queue = deque([root])
|
||||
def findBottomLeftValue(self, root):
|
||||
if root is None:
|
||||
return 0
|
||||
queue = deque()
|
||||
queue.append(root)
|
||||
result = 0
|
||||
while queue:
|
||||
size = len(queue)
|
||||
leftmost = queue[0].val
|
||||
for i in range(size):
|
||||
node = queue.popleft()
|
||||
if i == 0:
|
||||
result = node.val
|
||||
if node.left:
|
||||
queue.append(node.left)
|
||||
if node.right:
|
||||
queue.append(node.right)
|
||||
if not queue:
|
||||
return leftmost
|
||||
return result
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
|
|
|||
|
|
@ -237,66 +237,82 @@ class Solution {
|
|||
```
|
||||
## Python
|
||||
|
||||
递归
|
||||
递归法(版本一)利用中序递增,结合数组
|
||||
```python
|
||||
class Solution:
|
||||
def getMinimumDifference(self, root: TreeNode) -> int:
|
||||
res = []
|
||||
r = float("inf")
|
||||
def buildaList(root): //把二叉搜索树转换成有序数组
|
||||
if not root: return None
|
||||
if root.left: buildaList(root.left) //左
|
||||
res.append(root.val) //中
|
||||
if root.right: buildaList(root.right) //右
|
||||
return res
|
||||
|
||||
buildaList(root)
|
||||
for i in range(len(res)-1): // 统计有序数组的最小差值
|
||||
r = min(abs(res[i]-res[i+1]),r)
|
||||
return r
|
||||
|
||||
|
||||
class Solution: # 双指针法,不用数组 (同Carl写法) - 更快
|
||||
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
|
||||
global pre,minval
|
||||
pre = None
|
||||
minval = 10**5
|
||||
self.traversal(root)
|
||||
return minval
|
||||
def __init__(self):
|
||||
self.vec = []
|
||||
|
||||
def traversal(self,root):
|
||||
global pre,minval
|
||||
if not root: return None
|
||||
def traversal(self, root):
|
||||
if root is None:
|
||||
return
|
||||
self.traversal(root.left)
|
||||
if pre and root.val-pre.val<minval:
|
||||
minval = root.val-pre.val
|
||||
pre = root
|
||||
self.traversal(root.right)
|
||||
self.vec.append(root.val) # 将二叉搜索树转换为有序数组
|
||||
self.traversal(root.right)
|
||||
|
||||
def getMinimumDifference(self, root):
|
||||
self.vec = []
|
||||
self.traversal(root)
|
||||
if len(self.vec) < 2:
|
||||
return 0
|
||||
result = float('inf')
|
||||
for i in range(1, len(self.vec)):
|
||||
# 统计有序数组的最小差值
|
||||
result = min(result, self.vec[i] - self.vec[i - 1])
|
||||
return result
|
||||
|
||||
```
|
||||
|
||||
|
||||
迭代法-中序遍历
|
||||
|
||||
递归法(版本二)利用中序递增,找到该树最小值
|
||||
```python
|
||||
class Solution:
|
||||
def getMinimumDifference(self, root: TreeNode) -> int:
|
||||
def __init__(self):
|
||||
self.result = float('inf')
|
||||
self.pre = None
|
||||
|
||||
def traversal(self, cur):
|
||||
if cur is None:
|
||||
return
|
||||
self.traversal(cur.left) # 左
|
||||
if self.pre is not None: # 中
|
||||
self.result = min(self.result, cur.val - self.pre.val)
|
||||
self.pre = cur # 记录前一个
|
||||
self.traversal(cur.right) # 右
|
||||
|
||||
def getMinimumDifference(self, root):
|
||||
self.traversal(root)
|
||||
return self.result
|
||||
|
||||
|
||||
```
|
||||
|
||||
迭代法
|
||||
```python
|
||||
class Solution:
|
||||
def getMinimumDifference(self, root):
|
||||
stack = []
|
||||
cur = root
|
||||
pre = None
|
||||
result = float('inf')
|
||||
while cur or stack:
|
||||
if cur: # 指针来访问节点,访问到最底层
|
||||
stack.append(cur)
|
||||
cur = cur.left
|
||||
else: # 逐一处理节点
|
||||
|
||||
while cur is not None or len(stack) > 0:
|
||||
if cur is not None:
|
||||
stack.append(cur) # 将访问的节点放进栈
|
||||
cur = cur.left # 左
|
||||
else:
|
||||
cur = stack.pop()
|
||||
if pre: # 当前节点和前节点的值的差值
|
||||
result = min(result, abs(cur.val - pre.val))
|
||||
if pre is not None: # 中
|
||||
result = min(result, cur.val - pre.val)
|
||||
pre = cur
|
||||
cur = cur.right
|
||||
cur = cur.right # 右
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
## Go:
|
||||
|
||||
中序遍历,然后计算最小差值
|
||||
|
|
|
|||
|
|
@ -177,6 +177,8 @@ public:
|
|||
|
||||
|
||||
## Java
|
||||
**递归**
|
||||
|
||||
```Java
|
||||
class Solution {
|
||||
int sum;
|
||||
|
|
@ -198,10 +200,68 @@ class Solution {
|
|||
}
|
||||
}
|
||||
```
|
||||
**迭代**
|
||||
|
||||
```Java
|
||||
class Solution {
|
||||
//DFS iteraion統一迭代法
|
||||
public TreeNode convertBST(TreeNode root) {
|
||||
int pre = 0;
|
||||
Stack<TreeNode> stack = new Stack<>();
|
||||
if(root == null) //edge case check
|
||||
return null;
|
||||
|
||||
stack.add(root);
|
||||
|
||||
while(!stack.isEmpty()){
|
||||
TreeNode curr = stack.peek();
|
||||
//curr != null的狀況,只負責存node到stack中
|
||||
if(curr != null){
|
||||
stack.pop();
|
||||
if(curr.left != null) //左
|
||||
stack.add(curr.left);
|
||||
stack.add(curr); //中
|
||||
stack.add(null);
|
||||
if(curr.right != null) //右
|
||||
stack.add(curr.right);
|
||||
}else{
|
||||
//curr == null的狀況,只負責做單層邏輯
|
||||
stack.pop();
|
||||
TreeNode temp = stack.pop();
|
||||
temp.val += pre;
|
||||
pre = temp.val;
|
||||
}
|
||||
}
|
||||
return root;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 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
|
||||
class Solution:
|
||||
def convertBST(self, root: TreeNode) -> TreeNode:
|
||||
self.pre = 0 # 记录前一个节点的数值
|
||||
self.traversal(root)
|
||||
return root
|
||||
def traversal(self, cur):
|
||||
if cur is None:
|
||||
return
|
||||
self.traversal(cur.right)
|
||||
cur.val += self.pre
|
||||
self.pre = cur.val
|
||||
self.traversal(cur.left)
|
||||
|
||||
|
||||
```
|
||||
递归法(版本二)
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
|
|
@ -234,7 +294,32 @@ class Solution:
|
|||
return root
|
||||
|
||||
```
|
||||
**迭代**
|
||||
迭代法(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.pre = 0 # 记录前一个节点的数值
|
||||
|
||||
def traversal(self, root):
|
||||
stack = []
|
||||
cur = root
|
||||
while cur or stack:
|
||||
if cur:
|
||||
stack.append(cur)
|
||||
cur = cur.right # 右
|
||||
else:
|
||||
cur = stack.pop() # 中
|
||||
cur.val += self.pre
|
||||
self.pre = cur.val
|
||||
cur = cur.left # 左
|
||||
|
||||
def convertBST(self, root):
|
||||
self.pre = 0
|
||||
self.traversal(root)
|
||||
return root
|
||||
|
||||
```
|
||||
迭代法(版本二)
|
||||
```python
|
||||
class Solution:
|
||||
def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
|
||||
|
|
|
|||
|
|
@ -352,8 +352,7 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python
|
||||
|
||||
**递归法 - 前序遍历**
|
||||
(版本一) 递归 - 前序 - 修改root1
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
|
|
@ -377,8 +376,33 @@ class Solution:
|
|||
return root1 # ⚠️ 注意: 本题我们重复使用了题目给出的节点而不是创建新节点. 节省时间, 空间.
|
||||
|
||||
```
|
||||
(版本二) 递归 - 前序 - 新建root
|
||||
```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 mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
|
||||
# 递归终止条件:
|
||||
# 但凡有一个节点为空, 就立刻返回另外一个. 如果另外一个也为None就直接返回None.
|
||||
if not root1:
|
||||
return root2
|
||||
if not root2:
|
||||
return root1
|
||||
# 上面的递归终止条件保证了代码执行到这里root1, root2都非空.
|
||||
root = TreeNode() # 创建新节点
|
||||
root.val += root1.val + root2.val# 中
|
||||
root.left = self.mergeTrees(root1.left, root2.left) #左
|
||||
root.right = self.mergeTrees(root1.right, root2.right) # 右
|
||||
|
||||
return root # ⚠️ 注意: 本题我们创建了新节点.
|
||||
|
||||
**迭代法**
|
||||
```
|
||||
|
||||
(版本三) 迭代
|
||||
```python
|
||||
class Solution:
|
||||
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
|
||||
|
|
@ -413,7 +437,44 @@ class Solution:
|
|||
|
||||
return root1
|
||||
```
|
||||
(版本四) 迭代 + 代码优化
|
||||
```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
|
||||
from collections import deque
|
||||
|
||||
class Solution:
|
||||
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
|
||||
if not root1:
|
||||
return root2
|
||||
if not root2:
|
||||
return root1
|
||||
|
||||
queue = deque()
|
||||
queue.append((root1, root2))
|
||||
|
||||
while queue:
|
||||
node1, node2 = queue.popleft()
|
||||
node1.val += node2.val
|
||||
|
||||
if node1.left and node2.left:
|
||||
queue.append((node1.left, node2.left))
|
||||
elif not node1.left:
|
||||
node1.left = node2.left
|
||||
|
||||
if node1.right and node2.right:
|
||||
queue.append((node1.right, node2.right))
|
||||
elif not node1.right:
|
||||
node1.right = node2.right
|
||||
|
||||
return root1
|
||||
|
||||
|
||||
```
|
||||
### Go
|
||||
|
||||
```go
|
||||
|
|
|
|||
|
|
@ -238,33 +238,24 @@ Java:
|
|||
```java
|
||||
class Solution {
|
||||
public int countSubstrings(String s) {
|
||||
int len, ans = 0;
|
||||
if (s == null || (len = s.length()) < 1) return 0;
|
||||
//dp[i][j]:s字符串下标i到下标j的字串是否是一个回文串,即s[i, j]
|
||||
char[] chars = s.toCharArray();
|
||||
int len = chars.length;
|
||||
boolean[][] dp = new boolean[len][len];
|
||||
for (int j = 0; j < len; j++) {
|
||||
for (int i = 0; i <= j; i++) {
|
||||
//当两端字母一样时,才可以两端收缩进一步判断
|
||||
if (s.charAt(i) == s.charAt(j)) {
|
||||
//i++,j--,即两端收缩之后i,j指针指向同一个字符或者i超过j了,必然是一个回文串
|
||||
if (j - i < 3) {
|
||||
int result = 0;
|
||||
for (int i = len - 1; i >= 0; i--) {
|
||||
for (int j = i; j < len; j++) {
|
||||
if (chars[i] == chars[j]) {
|
||||
if (j - i <= 1) { // 情况一 和 情况二
|
||||
result++;
|
||||
dp[i][j] = true;
|
||||
} else if (dp[i + 1][j - 1]) { //情况三
|
||||
result++;
|
||||
dp[i][j] = true;
|
||||
} else {
|
||||
//否则通过收缩之后的字串判断
|
||||
dp[i][j] = dp[i + 1][j - 1];
|
||||
}
|
||||
} else {//两端字符不一样,不是回文串
|
||||
dp[i][j] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
//遍历每一个字串,统计回文串个数
|
||||
for (int i = 0; i < len; i++) {
|
||||
for (int j = 0; j < len; j++) {
|
||||
if (dp[i][j]) ans++;
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -259,52 +259,75 @@ 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
|
||||
class Solution:
|
||||
"""递归法 更快"""
|
||||
def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
|
||||
if not nums:
|
||||
return None
|
||||
maxvalue = max(nums)
|
||||
index = nums.index(maxvalue)
|
||||
if len(nums) == 1:
|
||||
return TreeNode(nums[0])
|
||||
node = TreeNode(0)
|
||||
# 找到数组中最大的值和对应的下标
|
||||
maxValue = 0
|
||||
maxValueIndex = 0
|
||||
for i in range(len(nums)):
|
||||
if nums[i] > maxValue:
|
||||
maxValue = nums[i]
|
||||
maxValueIndex = i
|
||||
node.val = maxValue
|
||||
# 最大值所在的下标左区间 构造左子树
|
||||
if maxValueIndex > 0:
|
||||
new_list = nums[:maxValueIndex]
|
||||
node.left = self.constructMaximumBinaryTree(new_list)
|
||||
# 最大值所在的下标右区间 构造右子树
|
||||
if maxValueIndex < len(nums) - 1:
|
||||
new_list = nums[maxValueIndex+1:]
|
||||
node.right = self.constructMaximumBinaryTree(new_list)
|
||||
return node
|
||||
|
||||
root = TreeNode(maxvalue)
|
||||
```
|
||||
(版本二) 使用下标
|
||||
```python
|
||||
|
||||
left = nums[:index]
|
||||
right = nums[index + 1:]
|
||||
|
||||
root.left = self.constructMaximumBinaryTree(left)
|
||||
root.right = self.constructMaximumBinaryTree(right)
|
||||
return root
|
||||
|
||||
class Solution:
|
||||
"""最大二叉树 递归法"""
|
||||
def traversal(self, nums: List[int], left: int, right: int) -> TreeNode:
|
||||
if left >= right:
|
||||
return None
|
||||
maxValueIndex = left
|
||||
for i in range(left + 1, right):
|
||||
if nums[i] > nums[maxValueIndex]:
|
||||
maxValueIndex = i
|
||||
root = TreeNode(nums[maxValueIndex])
|
||||
root.left = self.traversal(nums, left, maxValueIndex)
|
||||
root.right = self.traversal(nums, maxValueIndex + 1, right)
|
||||
return root
|
||||
|
||||
def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
|
||||
return self.traversal(nums, 0, len(nums))
|
||||
|
||||
def traversal(self, nums: List[int], begin: int, end: int) -> TreeNode:
|
||||
# 列表长度为0时返回空节点
|
||||
if begin == end:
|
||||
return None
|
||||
|
||||
# 找到最大的值和其对应的下标
|
||||
max_index = begin
|
||||
for i in range(begin, end):
|
||||
if nums[i] > nums[max_index]:
|
||||
max_index = i
|
||||
|
||||
# 构建当前节点
|
||||
root = TreeNode(nums[max_index])
|
||||
|
||||
# 递归构建左右子树
|
||||
root.left = self.traversal(nums, begin, max_index)
|
||||
root.right = self.traversal(nums, max_index + 1, end)
|
||||
|
||||
return root
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
(版本三) 使用切片
|
||||
|
||||
```python
|
||||
|
||||
class Solution:
|
||||
def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
|
||||
if not nums:
|
||||
return None
|
||||
max_val = max(nums)
|
||||
max_index = nums.index(max_val)
|
||||
node = TreeNode(max_val)
|
||||
node.left = self.constructMaximumBinaryTree(nums[:max_index])
|
||||
node.right = self.constructMaximumBinaryTree(nums[max_index+1:])
|
||||
return node
|
||||
|
||||
```
|
||||
### Go
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -248,6 +248,8 @@ public:
|
|||
|
||||
## Java
|
||||
|
||||
**递归**
|
||||
|
||||
```Java
|
||||
class Solution {
|
||||
public TreeNode trimBST(TreeNode root, int low, int high) {
|
||||
|
|
@ -269,66 +271,114 @@ 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
|
||||
class Solution:
|
||||
def trimBST(self, root: TreeNode, low: int, high: int) -> TreeNode:
|
||||
'''
|
||||
确认递归函数参数以及返回值:返回更新后剪枝后的当前root节点
|
||||
'''
|
||||
# Base Case
|
||||
if not root: return None
|
||||
|
||||
# 单层递归逻辑
|
||||
if root.val < low:
|
||||
# 若当前root节点小于左界:只考虑其右子树,用于替代更新后的其本身,抛弃其左子树整体
|
||||
return self.trimBST(root.right, low, high)
|
||||
|
||||
if high < root.val:
|
||||
# 若当前root节点大于右界:只考虑其左子树,用于替代更新后的其本身,抛弃其右子树整体
|
||||
return self.trimBST(root.left, low, high)
|
||||
|
||||
if low <= root.val <= high:
|
||||
root.left = self.trimBST(root.left, low, high)
|
||||
root.right = self.trimBST(root.right, low, high)
|
||||
# 返回更新后的剪枝过的当前节点root
|
||||
return root
|
||||
```
|
||||
|
||||
**迭代**
|
||||
|
||||
```Java
|
||||
class Solution {
|
||||
//iteration
|
||||
public TreeNode trimBST(TreeNode root, int low, int high) {
|
||||
if(root == null)
|
||||
return null;
|
||||
while(root != null && (root.val < low || root.val > high)){
|
||||
if(root.val < low)
|
||||
root = root.right;
|
||||
else
|
||||
root = root.left;
|
||||
}
|
||||
|
||||
TreeNode curr = root;
|
||||
|
||||
//deal with root's left sub-tree, and deal with the value smaller than low.
|
||||
while(curr != null){
|
||||
while(curr.left != null && curr.left.val < low){
|
||||
curr.left = curr.left.right;
|
||||
}
|
||||
curr = curr.left;
|
||||
}
|
||||
//go back to root;
|
||||
curr = root;
|
||||
|
||||
//deal with root's righg sub-tree, and deal with the value bigger than high.
|
||||
while(curr != null){
|
||||
while(curr.right != null && curr.right.val > high){
|
||||
curr.right = curr.right.left;
|
||||
}
|
||||
curr = curr.right;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
````
|
||||
|
||||
## Python
|
||||
|
||||
递归法(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
|
||||
if not root: return root
|
||||
# 处理头结点,让root移动到[L, R] 范围内,注意是左闭右开
|
||||
while root and (root.val < low or root.val > high):
|
||||
if root.val < low: # 小于L往右走
|
||||
root = root.right
|
||||
else: # 大于R往左走
|
||||
root = root.left
|
||||
# 此时root已经在[L, R] 范围内,处理左孩子元素小于L的情况
|
||||
def trimBST(self, root: TreeNode, low: int, high: int) -> TreeNode:
|
||||
if root is None:
|
||||
return None
|
||||
if root.val < low:
|
||||
# 寻找符合区间 [low, high] 的节点
|
||||
return self.trimBST(root.right, low, high)
|
||||
if root.val > high:
|
||||
# 寻找符合区间 [low, high] 的节点
|
||||
return self.trimBST(root.left, low, high)
|
||||
root.left = self.trimBST(root.left, low, high) # root.left 接入符合条件的左孩子
|
||||
root.right = self.trimBST(root.right, low, high) # root.right 接入符合条件的右孩子
|
||||
return root
|
||||
|
||||
```
|
||||
递归法(版本二)精简
|
||||
```python
|
||||
class Solution:
|
||||
def trimBST(self, root: TreeNode, low: int, high: int) -> TreeNode:
|
||||
if root is None:
|
||||
return None
|
||||
if root.val < low:
|
||||
return self.trimBST(root.right, low, high)
|
||||
if root.val > high:
|
||||
return self.trimBST(root.left, low, high)
|
||||
root.left = self.trimBST(root.left, low, high)
|
||||
root.right = self.trimBST(root.right, low, high)
|
||||
return root
|
||||
|
||||
|
||||
```
|
||||
|
||||
迭代法
|
||||
```python
|
||||
class Solution:
|
||||
def trimBST(self, root: TreeNode, L: int, R: int) -> TreeNode:
|
||||
if not root:
|
||||
return None
|
||||
|
||||
# 处理头结点,让root移动到[L, R] 范围内,注意是左闭右闭
|
||||
while root and (root.val < L or root.val > R):
|
||||
if root.val < L:
|
||||
root = root.right # 小于L往右走
|
||||
else:
|
||||
root = root.left # 大于R往左走
|
||||
|
||||
cur = root
|
||||
|
||||
# 此时root已经在[L, R] 范围内,处理左孩子元素小于L的情况
|
||||
while cur:
|
||||
while cur.left and cur.left.val < low:
|
||||
while cur.left and cur.left.val < L:
|
||||
cur.left = cur.left.right
|
||||
cur = cur.left
|
||||
# 此时root已经在[L, R] 范围内,处理右孩子大于R的情况
|
||||
|
||||
cur = root
|
||||
|
||||
# 此时root已经在[L, R] 范围内,处理右孩子大于R的情况
|
||||
while cur:
|
||||
while cur.right and cur.right.val > high:
|
||||
while cur.right and cur.right.val > R:
|
||||
cur.right = cur.right.left
|
||||
cur = cur.right
|
||||
|
||||
return root
|
||||
|
||||
```
|
||||
|
||||
## Go
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ class Solution {
|
|||
|
||||
### Python
|
||||
|
||||
递归法:
|
||||
(方法一) 递归
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
|
|
@ -250,12 +250,12 @@ class Solution:
|
|||
|
||||
```
|
||||
|
||||
迭代法:
|
||||
(方法二)迭代
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
|
||||
while root is not None:
|
||||
while root:
|
||||
if val < root.val: root = root.left
|
||||
elif val > root.val: root = root.right
|
||||
else: return root
|
||||
|
|
|
|||
|
|
@ -256,132 +256,118 @@ 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
|
||||
class Solution:
|
||||
def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
|
||||
# 返回更新后的以当前root为根节点的新树,方便用于更新上一层的父子节点关系链
|
||||
def __init__(self):
|
||||
self.parent = None
|
||||
|
||||
# Base Case
|
||||
if not root: return TreeNode(val)
|
||||
def traversal(self, cur, val):
|
||||
if cur is None:
|
||||
node = TreeNode(val)
|
||||
if val > self.parent.val:
|
||||
self.parent.right = node
|
||||
else:
|
||||
self.parent.left = node
|
||||
return
|
||||
|
||||
# 单层递归逻辑:
|
||||
if val < root.val:
|
||||
# 将val插入至当前root的左子树中合适的位置
|
||||
# 并更新当前root的左子树为包含目标val的新左子树
|
||||
root.left = self.insertIntoBST(root.left, val)
|
||||
self.parent = cur
|
||||
if cur.val > val:
|
||||
self.traversal(cur.left, val)
|
||||
if cur.val < val:
|
||||
self.traversal(cur.right, val)
|
||||
|
||||
if root.val < val:
|
||||
# 将val插入至当前root的右子树中合适的位置
|
||||
# 并更新当前root的右子树为包含目标val的新右子树
|
||||
root.right = self.insertIntoBST(root.right, val)
|
||||
|
||||
# 返回更新后的以当前root为根节点的新树
|
||||
def insertIntoBST(self, root, val):
|
||||
self.parent = TreeNode(0)
|
||||
if root is None:
|
||||
return TreeNode(val)
|
||||
self.traversal(root, val)
|
||||
return root
|
||||
|
||||
```
|
||||
|
||||
**递归法** - 无返回值
|
||||
递归法(版本二)
|
||||
```python
|
||||
class Solution:
|
||||
def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
|
||||
if not root:
|
||||
def insertIntoBST(self, root, val):
|
||||
if root is None:
|
||||
return TreeNode(val)
|
||||
parent = None
|
||||
def __traverse(cur: TreeNode, val: int) -> None:
|
||||
# 在函数运行的同时把新节点插入到该被插入的地方.
|
||||
nonlocal parent
|
||||
if not cur:
|
||||
new_node = TreeNode(val)
|
||||
if parent.val < val:
|
||||
parent.right = new_node
|
||||
else:
|
||||
parent.left = new_node
|
||||
return
|
||||
|
||||
parent = cur # 重点: parent的作用只有运行到上面if not cur:才会发挥出来.
|
||||
if cur.val < val:
|
||||
__traverse(cur.right, val)
|
||||
else:
|
||||
__traverse(cur.left, val)
|
||||
return
|
||||
__traverse(root, val)
|
||||
return root
|
||||
```
|
||||
|
||||
**递归法** - 无返回值 - another easier way
|
||||
```python
|
||||
class Solution:
|
||||
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
|
||||
newNode = TreeNode(val)
|
||||
if not root: return newNode
|
||||
|
||||
if not root.left and val < root.val:
|
||||
root.left = newNode
|
||||
if not root.right and val > root.val:
|
||||
root.right = newNode
|
||||
|
||||
if val < root.val:
|
||||
self.insertIntoBST(root.left, val)
|
||||
if val > root.val:
|
||||
self.insertIntoBST(root.right, val)
|
||||
|
||||
return root
|
||||
```
|
||||
|
||||
**递归法** - 无返回值 有注释 不用Helper function
|
||||
```python
|
||||
class Solution:
|
||||
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
|
||||
if not root: # for root==None
|
||||
return TreeNode(val)
|
||||
if root.val<val:
|
||||
if root.right==None: # find the parent
|
||||
root.right = TreeNode(val)
|
||||
else: # not found, keep searching
|
||||
self.insertIntoBST(root.right, val)
|
||||
if root.val>val:
|
||||
if root.left==None: # found the parent
|
||||
root.left = TreeNode(val)
|
||||
else: # not found, keep searching
|
||||
self.insertIntoBST(root.left, val)
|
||||
# return the final tree
|
||||
return root
|
||||
```
|
||||
|
||||
**迭代法**
|
||||
与无返回值的递归函数的思路大体一致
|
||||
```python
|
||||
class Solution:
|
||||
def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
|
||||
if not root:
|
||||
return TreeNode(val)
|
||||
parent = None # 此步可以省略
|
||||
cur = root
|
||||
|
||||
# 用while循环不断地找新节点的parent
|
||||
while cur:
|
||||
parent = cur # 首先保存当前非空节点作为下一次迭代的父节点
|
||||
if cur.val < val:
|
||||
cur = cur.right
|
||||
elif cur.val > val:
|
||||
while cur:
|
||||
parent = cur
|
||||
if val < cur.val:
|
||||
cur = cur.left
|
||||
|
||||
# 运行到这意味着已经跳出上面的while循环,
|
||||
# 同时意味着新节点的parent已经被找到.
|
||||
# parent已被找到, 新节点已经ready. 把两个节点黏在一起就好了.
|
||||
if parent.val > val:
|
||||
else:
|
||||
cur = cur.right
|
||||
if val < parent.val:
|
||||
parent.left = TreeNode(val)
|
||||
else:
|
||||
else:
|
||||
parent.right = TreeNode(val)
|
||||
|
||||
return root
|
||||
```
|
||||
|
||||
递归法(版本三)
|
||||
```python
|
||||
class Solution:
|
||||
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
|
||||
if root is None or root.val == val:
|
||||
return TreeNode(val)
|
||||
elif root.val > val:
|
||||
if root.left is None:
|
||||
root.left = TreeNode(val)
|
||||
else:
|
||||
self.insertIntoBST(root.left, val)
|
||||
elif root.val < val:
|
||||
if root.right is None:
|
||||
root.right = TreeNode(val)
|
||||
else:
|
||||
self.insertIntoBST(root.right, val)
|
||||
return root
|
||||
```
|
||||
|
||||
递归法(版本四)
|
||||
```python
|
||||
class Solution:
|
||||
def insertIntoBST(self, root, val):
|
||||
if root is None:
|
||||
node = TreeNode(val)
|
||||
return node
|
||||
|
||||
if root.val > val:
|
||||
root.left = self.insertIntoBST(root.left, val)
|
||||
if root.val < val:
|
||||
root.right = self.insertIntoBST(root.right, val)
|
||||
|
||||
return root
|
||||
|
||||
```
|
||||
|
||||
迭代法
|
||||
```python
|
||||
class Solution:
|
||||
def insertIntoBST(self, root, val):
|
||||
if root is None: # 如果根节点为空,创建新节点作为根节点并返回
|
||||
node = TreeNode(val)
|
||||
return node
|
||||
|
||||
cur = root
|
||||
parent = root # 记录上一个节点,用于连接新节点
|
||||
while cur is not None:
|
||||
parent = cur
|
||||
if cur.val > val:
|
||||
cur = cur.left
|
||||
else:
|
||||
cur = cur.right
|
||||
|
||||
node = TreeNode(val)
|
||||
if val < parent.val:
|
||||
parent.left = node # 将新节点连接到父节点的左子树
|
||||
else:
|
||||
parent.right = node # 将新节点连接到父节点的右子树
|
||||
|
||||
return root
|
||||
|
||||
|
||||
```
|
||||
-----
|
||||
|
|
|
|||
|
|
@ -203,7 +203,57 @@ public:
|
|||
|
||||
而且为了让 `if (dp[i][j] > result) result = dp[i][j];` 收集到全部结果,两层for训练一定从0开始遍历,这样需要加上 `&& i > 0 && j > 0`的判断。
|
||||
|
||||
相对于版本一来说还是多写了不少代码。而且逻辑上也复杂了一些。 优势就是dp数组的定义,更直观一点。
|
||||
对于基础不牢的小白来说,在推导出转移方程后可能疑惑上述代码为什么要从`i=0,j=0`遍历而不是从`i=1,j=1`开始遍历,原因在于这里如果不是从`i=0,j=0`位置开始遍历,会漏掉如下样例结果:
|
||||
```txt
|
||||
nums1 = [70,39,25,40,7]
|
||||
nums2 = [52,20,67,5,31]
|
||||
```
|
||||
|
||||
当然,如果你愿意也可以使用如下代码,与上面那个c++是同一思路:
|
||||
```java
|
||||
class Solution {
|
||||
public int findLength(int[] nums1, int[] nums2) {
|
||||
int len1 = nums1.length;
|
||||
int len2 = nums2.length;
|
||||
int[][] result = new int[len1][len2];
|
||||
|
||||
int maxresult = Integer.MIN_VALUE;
|
||||
|
||||
for(int i=0;i<len1;i++){
|
||||
if(nums1[i] == nums2[0])
|
||||
result[i][0] = 1;
|
||||
if(maxresult<result[i][0])
|
||||
maxresult = result[i][0];
|
||||
}
|
||||
|
||||
for(int j=0;j<len2;j++){
|
||||
if(nums1[0] == nums2[j])
|
||||
result[0][j] = 1;
|
||||
if(maxresult<result[0][j])
|
||||
maxresult = result[0][j];
|
||||
}
|
||||
|
||||
for(int i=1;i<len1;i++){
|
||||
for(int j=1;j<len2;j++){
|
||||
|
||||
if(nums1[i]==nums2[j])
|
||||
result[i][j] = result[i-1][j-1]+1;
|
||||
|
||||
if(maxresult<result[i][j])
|
||||
maxresult = result[i][j];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return maxresult;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
对于小白来说一定要明确dp数组中初始化的数据是什么
|
||||
|
||||
整体而言相对于版本一来说还是多写了不少代码。而且逻辑上也复杂了一些。 优势就是dp数组的定义,更直观一点。
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
|
|
|||
|
|
@ -164,17 +164,110 @@ class Solution {
|
|||
|
||||
|
||||
### Python:
|
||||
暴力
|
||||
```python
|
||||
class Solution:
|
||||
def monotoneIncreasingDigits(self, n: int) -> int:
|
||||
a = list(str(n))
|
||||
for i in range(len(a)-1,0,-1):
|
||||
if int(a[i]) < int(a[i-1]):
|
||||
a[i-1] = str(int(a[i-1]) - 1)
|
||||
a[i:] = '9' * (len(a) - i) #python不需要设置flag值,直接按长度给9就好了
|
||||
return int("".join(a))
|
||||
```
|
||||
def checkNum(self, num):
|
||||
max_digit = 10
|
||||
while num:
|
||||
digit = num % 10
|
||||
if max_digit >= digit:
|
||||
max_digit = digit
|
||||
else:
|
||||
return False
|
||||
num //= 10
|
||||
return True
|
||||
|
||||
def monotoneIncreasingDigits(self, N):
|
||||
for i in range(N, 0, -1):
|
||||
if self.checkNum(i):
|
||||
return i
|
||||
return 0
|
||||
|
||||
```
|
||||
贪心(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def monotoneIncreasingDigits(self, N: int) -> int:
|
||||
# 将整数转换为字符串
|
||||
strNum = str(N)
|
||||
# flag用来标记赋值9从哪里开始
|
||||
# 设置为字符串长度,为了防止第二个for循环在flag没有被赋值的情况下执行
|
||||
flag = len(strNum)
|
||||
|
||||
# 从右往左遍历字符串
|
||||
for i in range(len(strNum) - 1, 0, -1):
|
||||
# 如果当前字符比前一个字符小,说明需要修改前一个字符
|
||||
if strNum[i - 1] > strNum[i]:
|
||||
flag = i # 更新flag的值,记录需要修改的位置
|
||||
# 将前一个字符减1,以保证递增性质
|
||||
strNum = strNum[:i - 1] + str(int(strNum[i - 1]) - 1) + strNum[i:]
|
||||
|
||||
# 将flag位置及之后的字符都修改为9,以保证最大的递增数字
|
||||
for i in range(flag, len(strNum)):
|
||||
strNum = strNum[:i] + '9' + strNum[i + 1:]
|
||||
|
||||
# 将最终的字符串转换回整数并返回
|
||||
return int(strNum)
|
||||
|
||||
```
|
||||
贪心(版本二)
|
||||
```python
|
||||
class Solution:
|
||||
def monotoneIncreasingDigits(self, N: int) -> int:
|
||||
# 将整数转换为字符串
|
||||
strNum = list(str(N))
|
||||
|
||||
# 从右往左遍历字符串
|
||||
for i in range(len(strNum) - 1, 0, -1):
|
||||
# 如果当前字符比前一个字符小,说明需要修改前一个字符
|
||||
if strNum[i - 1] > strNum[i]:
|
||||
strNum[i - 1] = str(int(strNum[i - 1]) - 1) # 将前一个字符减1
|
||||
# 将修改位置后面的字符都设置为9,因为修改前一个字符可能破坏了递增性质
|
||||
for j in range(i, len(strNum)):
|
||||
strNum[j] = '9'
|
||||
|
||||
# 将列表转换为字符串,并将字符串转换为整数并返回
|
||||
return int(''.join(strNum))
|
||||
|
||||
|
||||
```
|
||||
贪心(版本三)
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def monotoneIncreasingDigits(self, N: int) -> int:
|
||||
# 将整数转换为字符串
|
||||
strNum = list(str(N))
|
||||
|
||||
# 从右往左遍历字符串
|
||||
for i in range(len(strNum) - 1, 0, -1):
|
||||
# 如果当前字符比前一个字符小,说明需要修改前一个字符
|
||||
if strNum[i - 1] > strNum[i]:
|
||||
strNum[i - 1] = str(int(strNum[i - 1]) - 1) # 将前一个字符减1
|
||||
# 将修改位置后面的字符都设置为9,因为修改前一个字符可能破坏了递增性质
|
||||
strNum[i:] = '9' * (len(strNum) - i)
|
||||
|
||||
# 将列表转换为字符串,并将字符串转换为整数并返回
|
||||
return int(''.join(strNum))
|
||||
|
||||
```
|
||||
贪心(版本四)精简
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def monotoneIncreasingDigits(self, N: int) -> int:
|
||||
strNum = str(N)
|
||||
for i in range(len(strNum) - 1, 0, -1):
|
||||
# 如果当前字符比前一个字符小,说明需要修改前一个字符
|
||||
if strNum[i - 1] > strNum[i]:
|
||||
# 将前一个字符减1,以保证递增性质
|
||||
# 使用字符串切片操作将修改后的前面部分与后面部分进行拼接
|
||||
strNum = strNum[:i - 1] + str(int(strNum[i - 1]) - 1) + '9' * (len(strNum) - i)
|
||||
return int(strNum)
|
||||
|
||||
|
||||
```
|
||||
### Go
|
||||
```go
|
||||
func monotoneIncreasingDigits(N int) int {
|
||||
|
|
|
|||
|
|
@ -245,26 +245,42 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python
|
||||
|
||||
动态规划(版本一)
|
||||
```python
|
||||
# 第一步不支付费用
|
||||
class Solution:
|
||||
def minCostClimbingStairs(self, cost: List[int]) -> int:
|
||||
n = len(cost)
|
||||
dp = [0]*(n+1) # 到达前两步费用为0
|
||||
for i in range(2, n+1):
|
||||
dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2])
|
||||
return dp[-1]
|
||||
```
|
||||
```python
|
||||
# 第一步支付费用
|
||||
|
||||
class Solution:
|
||||
def minCostClimbingStairs(self, cost: List[int]) -> int:
|
||||
dp = [0] * (len(cost) + 1)
|
||||
dp[0] = 0
|
||||
dp[1] = 0
|
||||
dp[0] = 0 # 初始值,表示从起点开始不需要花费体力
|
||||
dp[1] = 0 # 初始值,表示经过第一步不需要花费体力
|
||||
|
||||
for i in range(2, len(cost) + 1):
|
||||
dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i-2])
|
||||
return dp[len(cost)]
|
||||
# 在第i步,可以选择从前一步(i-1)花费体力到达当前步,或者从前两步(i-2)花费体力到达当前步
|
||||
# 选择其中花费体力较小的路径,加上当前步的花费,更新dp数组
|
||||
dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2])
|
||||
|
||||
return dp[len(cost)] # 返回到达楼顶的最小花费
|
||||
|
||||
```
|
||||
动态规划(版本二)
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def minCostClimbingStairs(self, cost: List[int]) -> int:
|
||||
dp0 = 0 # 初始值,表示从起点开始不需要花费体力
|
||||
dp1 = 0 # 初始值,表示经过第一步不需要花费体力
|
||||
|
||||
for i in range(2, len(cost) + 1):
|
||||
# 在第i步,可以选择从前一步(i-1)花费体力到达当前步,或者从前两步(i-2)花费体力到达当前步
|
||||
# 选择其中花费体力较小的路径,加上当前步的花费,得到当前步的最小花费
|
||||
dpi = min(dp1 + cost[i - 1], dp0 + cost[i - 2])
|
||||
|
||||
dp0 = dp1 # 更新dp0为前一步的值,即上一次循环中的dp1
|
||||
dp1 = dpi # 更新dp1为当前步的最小花费
|
||||
|
||||
return dp1 # 返回到达楼顶的最小花费
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -231,83 +231,56 @@ class Solution{
|
|||
```
|
||||
|
||||
### Python
|
||||
贪心(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def partitionLabels(self, s: str) -> List[int]:
|
||||
hash = [0] * 26
|
||||
for i in range(len(s)):
|
||||
hash[ord(s[i]) - ord('a')] = i
|
||||
last_occurrence = {} # 存储每个字符最后出现的位置
|
||||
for i, ch in enumerate(s):
|
||||
last_occurrence[ch] = i
|
||||
|
||||
result = []
|
||||
left = 0
|
||||
right = 0
|
||||
for i in range(len(s)):
|
||||
right = max(right, hash[ord(s[i]) - ord('a')])
|
||||
if i == right:
|
||||
result.append(right - left + 1)
|
||||
left = i + 1
|
||||
start = 0
|
||||
end = 0
|
||||
for i, ch in enumerate(s):
|
||||
end = max(end, last_occurrence[ch]) # 找到当前字符出现的最远位置
|
||||
if i == end: # 如果当前位置是最远位置,表示可以分割出一个区间
|
||||
result.append(end - start + 1)
|
||||
start = i + 1
|
||||
|
||||
return result
|
||||
|
||||
# 解法二(不相交区间法)
|
||||
|
||||
```
|
||||
贪心(版本二)与452.用最少数量的箭引爆气球 (opens new window)、435.无重叠区间 (opens new window)相同的思路。
|
||||
```python
|
||||
class Solution:
|
||||
def partitionLabels(self, s: str) -> List[int]:
|
||||
# 记录每个字母出现的区间
|
||||
def getBord(s):
|
||||
hash = [[-float('inf')] * 2 for _ in range(26)]
|
||||
for i in range(len(s)):
|
||||
if hash[ord(s[i]) - ord('a')][0] == -float('inf'):
|
||||
hash[ord(s[i]) - ord('a')][0] = i
|
||||
hash[ord(s[i]) - ord('a')][1] = i
|
||||
# 去除字符串中未出现的字母所占用区间
|
||||
hash_filter = []
|
||||
for item in hash:
|
||||
if item[0] != -float('inf'): hash_filter.append(item)
|
||||
return hash_filter
|
||||
|
||||
# 得到无重叠区间题意中的输入样例格式:区间列表
|
||||
hash = getBord(s)
|
||||
# 按照左边界从小到大排序
|
||||
hash.sort(key= lambda x: x[0])
|
||||
res = []
|
||||
left = 0
|
||||
# 记录最大右边界
|
||||
right = hash[0][1]
|
||||
def countLabels(self, s):
|
||||
# 初始化一个长度为26的区间列表,初始值为负无穷
|
||||
hash = [[float('-inf'), float('-inf')] for _ in range(26)]
|
||||
hash_filter = []
|
||||
for i in range(len(s)):
|
||||
if hash[ord(s[i]) - ord('a')][0] == float('-inf'):
|
||||
hash[ord(s[i]) - ord('a')][0] = i
|
||||
hash[ord(s[i]) - ord('a')][1] = i
|
||||
for i in range(len(hash)):
|
||||
# 一旦下一区间左边界大于当前右边界,即可认为出现分割点
|
||||
if hash[i][0] > right:
|
||||
res.append(right - left + 1)
|
||||
left = hash[i][0]
|
||||
# 实时更新最大右边界
|
||||
right = max(right, hash[i][1])
|
||||
# 最右侧区间(字符串长度为1时的特殊情况也包含于其中)
|
||||
res.append(right - left + 1)
|
||||
if hash[i][0] != float('-inf'):
|
||||
hash_filter.append(hash[i])
|
||||
return hash_filter
|
||||
|
||||
def partitionLabels(self, s):
|
||||
res = []
|
||||
hash = self.countLabels(s)
|
||||
hash.sort(key=lambda x: x[0]) # 按左边界从小到大排序
|
||||
rightBoard = hash[0][1] # 记录最大右边界
|
||||
leftBoard = 0
|
||||
for i in range(1, len(hash)):
|
||||
if hash[i][0] > rightBoard: # 出现分割点
|
||||
res.append(rightBoard - leftBoard + 1)
|
||||
leftBoard = hash[i][0]
|
||||
rightBoard = max(rightBoard, hash[i][1])
|
||||
res.append(rightBoard - leftBoard + 1) # 最右端
|
||||
return res
|
||||
|
||||
# 解法三:区间合并法 (结合下一题 56. Merge Intervals 的写法)
|
||||
class Solution: #
|
||||
def partitionLabels(self, s: str) -> List[int]:
|
||||
aaa = list(set(s))
|
||||
#aaa.sort()
|
||||
bbb = list(s)
|
||||
ccc = []
|
||||
for i in reversed(bbb):
|
||||
ccc.append(i)
|
||||
intervals = []
|
||||
for i in range(len(aaa)):
|
||||
intervals.append([bbb.index(aaa[i]),len(bbb)-ccc.index(aaa[i])-1])
|
||||
# 先求出各个字母的存在区间,之后利用区间合并方法得出所有不相邻的最大区间。
|
||||
intervals.sort(key = lambda x:x[0])
|
||||
newinterval = []
|
||||
left, right = intervals[0][0], intervals[0][1]
|
||||
for i in range(1,len(intervals)):
|
||||
if intervals[i][0] in range(left, right+1):
|
||||
right = max(intervals[i][1],intervals[i-1][1],right)
|
||||
left = min(intervals[i-1][0],left)
|
||||
else:
|
||||
newinterval.append(right-left+1)
|
||||
left = intervals[i][0]
|
||||
right = intervals[i][1]
|
||||
newinterval.append(right-left+1)
|
||||
return newinterval
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -164,24 +164,39 @@ class Solution {
|
|||
```python
|
||||
class Solution:
|
||||
def lemonadeChange(self, bills: List[int]) -> bool:
|
||||
five, ten = 0, 0
|
||||
five = 0
|
||||
ten = 0
|
||||
twenty = 0
|
||||
|
||||
for bill in bills:
|
||||
# 情况一:收到5美元
|
||||
if bill == 5:
|
||||
five += 1
|
||||
elif bill == 10:
|
||||
if five < 1: return False
|
||||
five -= 1
|
||||
|
||||
# 情况二:收到10美元
|
||||
if bill == 10:
|
||||
if five <= 0:
|
||||
return False
|
||||
ten += 1
|
||||
else:
|
||||
if ten > 0 and five > 0:
|
||||
ten -= 1
|
||||
five -= 1
|
||||
|
||||
# 情况三:收到20美元
|
||||
if bill == 20:
|
||||
# 先尝试使用10美元和5美元找零
|
||||
if five > 0 and ten > 0:
|
||||
five -= 1
|
||||
elif five > 2:
|
||||
ten -= 1
|
||||
#twenty += 1
|
||||
# 如果无法使用10美元找零,则尝试使用三张5美元找零
|
||||
elif five >= 3:
|
||||
five -= 3
|
||||
#twenty += 1
|
||||
else:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -371,56 +371,104 @@ class Solution {
|
|||
|
||||
|
||||
### Python
|
||||
|
||||
贪心(版本一)
|
||||
```python
|
||||
class Solution:
|
||||
def minCameraCover(self, root: TreeNode) -> int:
|
||||
# Greedy Algo:
|
||||
# Greedy Algo:
|
||||
# 从下往上安装摄像头:跳过leaves这样安装数量最少,局部最优 -> 全局最优
|
||||
# 先给leaves的父节点安装,然后每隔两层节点安装一个摄像头,直到Head
|
||||
# 0: 该节点未覆盖
|
||||
# 1: 该节点有摄像头
|
||||
# 2: 该节点有覆盖
|
||||
def minCameraCover(self, root: TreeNode) -> int:
|
||||
# 定义递归函数
|
||||
result = [0] # 用于记录摄像头的安装数量
|
||||
if self.traversal(root, result) == 0:
|
||||
result[0] += 1
|
||||
|
||||
result = 0
|
||||
# 从下往上遍历:后序(左右中)
|
||||
def traversal(curr: TreeNode) -> int:
|
||||
nonlocal result
|
||||
return result[0]
|
||||
|
||||
if not curr: return 2
|
||||
left = traversal(curr.left)
|
||||
right = traversal(curr.right)
|
||||
|
||||
def traversal(self, cur: TreeNode, result: List[int]) -> int:
|
||||
if not cur:
|
||||
return 2
|
||||
|
||||
# Case 1:
|
||||
# 左右节点都有覆盖
|
||||
if left == 2 and right == 2:
|
||||
return 0
|
||||
left = self.traversal(cur.left, result)
|
||||
right = self.traversal(cur.right, result)
|
||||
|
||||
# Case 2:
|
||||
# left == 0 && right == 0 左右节点无覆盖
|
||||
# left == 1 && right == 0 左节点有摄像头,右节点无覆盖
|
||||
# left == 0 && right == 1 左节点有无覆盖,右节点摄像头
|
||||
# left == 0 && right == 2 左节点无覆盖,右节点覆盖
|
||||
# left == 2 && right == 0 左节点覆盖,右节点无覆盖
|
||||
elif left == 0 or right == 0:
|
||||
result += 1
|
||||
return 1
|
||||
# 情况1: 左右节点都有覆盖
|
||||
if left == 2 and right == 2:
|
||||
return 0
|
||||
|
||||
# Case 3:
|
||||
# left == 1 && right == 2 左节点有摄像头,右节点有覆盖
|
||||
# left == 2 && right == 1 左节点有覆盖,右节点有摄像头
|
||||
# left == 1 && right == 1 左右节点都有摄像头
|
||||
elif left == 1 or right == 1:
|
||||
return 2
|
||||
# 情况2:
|
||||
# left == 0 && right == 0 左右节点无覆盖
|
||||
# left == 1 && right == 0 左节点有摄像头,右节点无覆盖
|
||||
# left == 0 && right == 1 左节点无覆盖,右节点有摄像头
|
||||
# left == 0 && right == 2 左节点无覆盖,右节点覆盖
|
||||
# left == 2 && right == 0 左节点覆盖,右节点无覆盖
|
||||
if left == 0 or right == 0:
|
||||
result[0] += 1
|
||||
return 1
|
||||
|
||||
# 其他情况前段代码均已覆盖
|
||||
# 情况3:
|
||||
# left == 1 && right == 2 左节点有摄像头,右节点有覆盖
|
||||
# left == 2 && right == 1 左节点有覆盖,右节点有摄像头
|
||||
# left == 1 && right == 1 左右节点都有摄像头
|
||||
if left == 1 or right == 1:
|
||||
return 2
|
||||
|
||||
if traversal(root) == 0:
|
||||
result += 1
|
||||
|
||||
return result
|
||||
```
|
||||
贪心(版本二)利用elif精简代码
|
||||
```python
|
||||
class Solution:
|
||||
# Greedy Algo:
|
||||
# 从下往上安装摄像头:跳过leaves这样安装数量最少,局部最优 -> 全局最优
|
||||
# 先给leaves的父节点安装,然后每隔两层节点安装一个摄像头,直到Head
|
||||
# 0: 该节点未覆盖
|
||||
# 1: 该节点有摄像头
|
||||
# 2: 该节点有覆盖
|
||||
def minCameraCover(self, root: TreeNode) -> int:
|
||||
# 定义递归函数
|
||||
result = [0] # 用于记录摄像头的安装数量
|
||||
if self.traversal(root, result) == 0:
|
||||
result[0] += 1
|
||||
|
||||
return result[0]
|
||||
|
||||
|
||||
def traversal(self, cur: TreeNode, result: List[int]) -> int:
|
||||
if not cur:
|
||||
return 2
|
||||
|
||||
left = self.traversal(cur.left, result)
|
||||
right = self.traversal(cur.right, result)
|
||||
|
||||
# 情况1: 左右节点都有覆盖
|
||||
if left == 2 and right == 2:
|
||||
return 0
|
||||
|
||||
# 情况2:
|
||||
# left == 0 && right == 0 左右节点无覆盖
|
||||
# left == 1 && right == 0 左节点有摄像头,右节点无覆盖
|
||||
# left == 0 && right == 1 左节点无覆盖,右节点有摄像头
|
||||
# left == 0 && right == 2 左节点无覆盖,右节点覆盖
|
||||
# left == 2 && right == 0 左节点覆盖,右节点无覆盖
|
||||
elif left == 0 or right == 0:
|
||||
result[0] += 1
|
||||
return 1
|
||||
|
||||
# 情况3:
|
||||
# left == 1 && right == 2 左节点有摄像头,右节点有覆盖
|
||||
# left == 2 && right == 1 左节点有覆盖,右节点有摄像头
|
||||
# left == 1 && right == 1 左右节点都有摄像头
|
||||
else:
|
||||
return 2
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
### Go
|
||||
|
||||
```go
|
||||
|
|
|
|||
|
|
@ -488,6 +488,14 @@ public class Solution {
|
|||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
C# LINQ:
|
||||
```csharp
|
||||
public class Solution {
|
||||
public int[] SortedSquares(int[] nums) {
|
||||
return nums.Select(x => x * x).OrderBy(x => x).ToArray();
|
||||
}
|
||||
}
|
||||
```
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
|
|
|
|||
|
|
@ -131,17 +131,23 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python
|
||||
贪心
|
||||
```python
|
||||
class Solution:
|
||||
def largestSumAfterKNegations(self, A: List[int], K: int) -> int:
|
||||
A = sorted(A, key=abs, reverse=True) # 将A按绝对值从大到小排列
|
||||
for i in range(len(A)):
|
||||
if K > 0 and A[i] < 0:
|
||||
A.sort(key=lambda x: abs(x), reverse=True) # 第一步:按照绝对值降序排序数组A
|
||||
|
||||
for i in range(len(A)): # 第二步:执行K次取反操作
|
||||
if A[i] < 0 and K > 0:
|
||||
A[i] *= -1
|
||||
K -= 1
|
||||
if K > 0:
|
||||
A[-1] *= (-1)**K #取A最后一个数只需要写-1
|
||||
return sum(A)
|
||||
|
||||
if K % 2 == 1: # 第三步:如果K还有剩余次数,将绝对值最小的元素取反
|
||||
A[-1] *= -1
|
||||
|
||||
result = sum(A) # 第四步:计算数组A的元素和
|
||||
return result
|
||||
|
||||
```
|
||||
|
||||
### Go
|
||||
|
|
|
|||
|
|
@ -224,18 +224,79 @@ class Solution {
|
|||
```
|
||||
|
||||
### Python:
|
||||
卡哥版
|
||||
```python
|
||||
class Solution:
|
||||
def lastStoneWeightII(self, stones: List[int]) -> int:
|
||||
sumweight = sum(stones)
|
||||
target = sumweight // 2
|
||||
dp = [0] * (target + 1)
|
||||
for i in range(len(stones)):
|
||||
for j in range(target, stones[i] - 1, -1):
|
||||
dp[j] = max(dp[j], dp[j - stones[i]] + stones[i])
|
||||
return sumweight - 2 * dp[target]
|
||||
```
|
||||
dp = [0] * 15001
|
||||
total_sum = sum(stones)
|
||||
target = total_sum // 2
|
||||
|
||||
for stone in stones: # 遍历物品
|
||||
for j in range(target, stone - 1, -1): # 遍历背包
|
||||
dp[j] = max(dp[j], dp[j - stone] + stone)
|
||||
|
||||
return total_sum - dp[target] - dp[target]
|
||||
|
||||
```
|
||||
二维DP版
|
||||
```python
|
||||
class Solution:
|
||||
def lastStoneWeightII(self, stones: List[int]) -> int:
|
||||
total_sum = sum(stones)
|
||||
target = total_sum // 2
|
||||
|
||||
# 创建二维dp数组,行数为石头的数量加1,列数为target加1
|
||||
# dp[i][j]表示前i个石头能否组成总重量为j
|
||||
dp = [[False] * (target + 1) for _ in range(len(stones) + 1)]
|
||||
|
||||
# 初始化第一列,表示总重量为0时,前i个石头都能组成
|
||||
for i in range(len(stones) + 1):
|
||||
dp[i][0] = True
|
||||
|
||||
for i in range(1, len(stones) + 1):
|
||||
for j in range(1, target + 1):
|
||||
# 如果当前石头重量大于当前目标重量j,则无法选择该石头
|
||||
if stones[i - 1] > j:
|
||||
dp[i][j] = dp[i - 1][j]
|
||||
else:
|
||||
# 可选择该石头或不选择该石头
|
||||
dp[i][j] = dp[i - 1][j] or dp[i - 1][j - stones[i - 1]]
|
||||
|
||||
# 找到最大的重量i,使得dp[len(stones)][i]为True
|
||||
# 返回总重量减去两倍的最接近总重量一半的重量
|
||||
for i in range(target, -1, -1):
|
||||
if dp[len(stones)][i]:
|
||||
return total_sum - 2 * i
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
```
|
||||
一维DP版
|
||||
```python
|
||||
class Solution:
|
||||
def lastStoneWeightII(self, stones):
|
||||
total_sum = sum(stones)
|
||||
target = total_sum // 2
|
||||
dp = [False] * (target + 1)
|
||||
dp[0] = True
|
||||
|
||||
for stone in stones:
|
||||
for j in range(target, stone - 1, -1):
|
||||
# 判断当前重量是否可以通过选择之前的石头得到或选择当前石头和之前的石头得到
|
||||
dp[j] = dp[j] or dp[j - stone]
|
||||
|
||||
for i in range(target, -1, -1):
|
||||
if dp[i]:
|
||||
# 返回剩余石头的重量,即总重量减去两倍的最接近总重量一半的重量
|
||||
return total_sum - 2 * i
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
```
|
||||
### Go:
|
||||
```go
|
||||
func lastStoneWeightII(stones []int) int {
|
||||
|
|
@ -379,8 +440,23 @@ object Solution {
|
|||
}
|
||||
```
|
||||
|
||||
### Rust
|
||||
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn last_stone_weight_ii(stones: Vec<i32>) -> i32 {
|
||||
let sum = stones.iter().sum::<i32>();
|
||||
let target = sum as usize / 2;
|
||||
let mut dp = vec![0; target + 1];
|
||||
for s in stones {
|
||||
for j in (s as usize..=target).rev() {
|
||||
dp[j] = dp[j].max(dp[j - s as usize] + s);
|
||||
}
|
||||
}
|
||||
sum - dp[target] * 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
|
|
|
|||
|
|
@ -195,15 +195,16 @@ Java:
|
|||
```java
|
||||
public class TreeNode {
|
||||
int val;
|
||||
TreeNode left;
|
||||
TreeNode right;
|
||||
TreeNode() {}
|
||||
TreeNode(int val) { this.val = val; }
|
||||
TreeNode(int val, TreeNode left, TreeNode right) {
|
||||
this.val = val;
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
TreeNode left;
|
||||
TreeNode right;
|
||||
|
||||
TreeNode() {}
|
||||
TreeNode(int val) { this.val = val; }
|
||||
TreeNode(int val, TreeNode left, TreeNode right) {
|
||||
this.val = val;
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -212,10 +213,10 @@ Python:
|
|||
|
||||
```python
|
||||
class TreeNode:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
self.left = None
|
||||
self.right = None
|
||||
def __init__(self, val, left = None, right = None):
|
||||
self.val = val
|
||||
self.left = left
|
||||
self.right = right
|
||||
```
|
||||
|
||||
Go:
|
||||
|
|
|
|||
|
|
@ -356,76 +356,80 @@ Python:
|
|||
|
||||
```python
|
||||
class Solution:
|
||||
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
|
||||
res = []
|
||||
nums.sort()
|
||||
def backtracking(start, path):
|
||||
res.append(path)
|
||||
uset = set()
|
||||
for i in range(start, len(nums)):
|
||||
if nums[i] not in uset:
|
||||
backtracking(i + 1, path + [nums[i]])
|
||||
uset.add(nums[i])
|
||||
def subsetsWithDup(self, nums):
|
||||
nums.sort() # 去重需要排序
|
||||
result = []
|
||||
self.backtracking(nums, 0, [], result)
|
||||
return result
|
||||
|
||||
def backtracking(self, nums, startIndex, path, result):
|
||||
result.append(path[:])
|
||||
used = set()
|
||||
for i in range(startIndex, len(nums)):
|
||||
if nums[i] in used:
|
||||
continue
|
||||
used.add(nums[i])
|
||||
path.append(nums[i])
|
||||
self.backtracking(nums, i + 1, path, result)
|
||||
path.pop()
|
||||
|
||||
backtracking(0, [])
|
||||
return res
|
||||
```
|
||||
|
||||
**40. 组合总和 II**
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
|
||||
|
||||
res = []
|
||||
def combinationSum2(self, candidates, target):
|
||||
candidates.sort()
|
||||
result = []
|
||||
self.backtracking(candidates, target, 0, 0, [], result)
|
||||
return result
|
||||
|
||||
def backtracking(start, path):
|
||||
if sum(path) == target:
|
||||
res.append(path)
|
||||
elif sum(path) < target:
|
||||
used = set()
|
||||
for i in range(start, len(candidates)):
|
||||
if candidates[i] in used:
|
||||
continue
|
||||
else:
|
||||
used.add(candidates[i])
|
||||
backtracking(i + 1, path + [candidates[i]])
|
||||
|
||||
backtracking(0, [])
|
||||
def backtracking(self, candidates, target, sum, startIndex, path, result):
|
||||
if sum == target:
|
||||
result.append(path[:])
|
||||
return
|
||||
used = set()
|
||||
for i in range(startIndex, len(candidates)):
|
||||
if sum + candidates[i] > target:
|
||||
break
|
||||
if candidates[i] in used:
|
||||
continue
|
||||
used.add(candidates[i])
|
||||
sum += candidates[i]
|
||||
path.append(candidates[i])
|
||||
self.backtracking(candidates, target, sum, i + 1, path, result)
|
||||
sum -= candidates[i]
|
||||
path.pop()
|
||||
|
||||
return res
|
||||
```
|
||||
|
||||
**47. 全排列 II**
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
|
||||
path = []
|
||||
res = []
|
||||
used = [False]*len(nums)
|
||||
def permuteUnique(self, nums):
|
||||
nums.sort() # 排序
|
||||
result = []
|
||||
self.backtracking(nums, [False] * len(nums), [], result)
|
||||
return result
|
||||
|
||||
def backtracking():
|
||||
if len(path) == len(nums):
|
||||
res.append(path.copy())
|
||||
|
||||
deduplicate = set()
|
||||
for i, num in enumerate(nums):
|
||||
if used[i] == True:
|
||||
continue
|
||||
if num in deduplicate:
|
||||
continue
|
||||
def backtracking(self, nums, used, path, result):
|
||||
if len(path) == len(nums):
|
||||
result.append(path[:])
|
||||
return
|
||||
used_set = set()
|
||||
for i in range(len(nums)):
|
||||
if nums[i] in used_set:
|
||||
continue
|
||||
if not used[i]:
|
||||
used_set.add(nums[i])
|
||||
used[i] = True
|
||||
path.append(nums[i])
|
||||
backtracking()
|
||||
used[i] = False
|
||||
self.backtracking(nums, used, path, result)
|
||||
path.pop()
|
||||
deduplicate.add(num)
|
||||
|
||||
backtracking()
|
||||
used[i] = False
|
||||
|
||||
return res
|
||||
```
|
||||
|
||||
JavaScript:
|
||||
|
|
|
|||
|
|
@ -339,38 +339,63 @@ public class BagProblem {
|
|||
```
|
||||
|
||||
### python
|
||||
|
||||
无参数版
|
||||
```python
|
||||
def test_2_wei_bag_problem1(bag_size, weight, value) -> int:
|
||||
rows, cols = len(weight), bag_size + 1
|
||||
dp = [[0 for _ in range(cols)] for _ in range(rows)]
|
||||
def test_2_wei_bag_problem1():
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
bagweight = 4
|
||||
|
||||
# 初始化dp数组.
|
||||
for i in range(rows):
|
||||
dp[i][0] = 0
|
||||
first_item_weight, first_item_value = weight[0], value[0]
|
||||
for j in range(1, cols):
|
||||
if first_item_weight <= j:
|
||||
dp[0][j] = first_item_value
|
||||
# 二维数组
|
||||
dp = [[0] * (bagweight + 1) for _ in range(len(weight))]
|
||||
|
||||
# 更新dp数组: 先遍历物品, 再遍历背包.
|
||||
for i in range(1, len(weight)):
|
||||
cur_weight, cur_val = weight[i], value[i]
|
||||
for j in range(1, cols):
|
||||
if cur_weight > j: # 说明背包装不下当前物品.
|
||||
dp[i][j] = dp[i - 1][j] # 所以不装当前物品.
|
||||
else:
|
||||
# 定义dp数组: dp[i][j] 前i个物品里,放进容量为j的背包,价值总和最大是多少。
|
||||
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - cur_weight]+ cur_val)
|
||||
# 初始化
|
||||
for j in range(weight[0], bagweight + 1):
|
||||
dp[0][j] = value[0]
|
||||
|
||||
print(dp)
|
||||
# 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])
|
||||
|
||||
print(dp[len(weight) - 1][bagweight])
|
||||
|
||||
test_2_wei_bag_problem1()
|
||||
|
||||
```
|
||||
有参数版
|
||||
```python
|
||||
def test_2_wei_bag_problem1(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__":
|
||||
bag_size = 4
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
test_2_wei_bag_problem1(bag_size, weight, value)
|
||||
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
bagweight = 4
|
||||
|
||||
result = test_2_wei_bag_problem1(weight, value, bagweight)
|
||||
print(result)
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -246,25 +246,46 @@ int main() {
|
|||
|
||||
|
||||
### Python
|
||||
无参版
|
||||
```python
|
||||
def test_1_wei_bag_problem():
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
bag_weight = 4
|
||||
# 初始化: 全为0
|
||||
dp = [0] * (bag_weight + 1)
|
||||
bagWeight = 4
|
||||
|
||||
# 先遍历物品, 再遍历背包容量
|
||||
for i in range(len(weight)):
|
||||
for j in range(bag_weight, weight[i] - 1, -1):
|
||||
# 递归公式
|
||||
# 初始化
|
||||
dp = [0] * (bagWeight + 1)
|
||||
for i in range(len(weight)): # 遍历物品
|
||||
for j in range(bagWeight, weight[i] - 1, -1): # 遍历背包容量
|
||||
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
|
||||
|
||||
print(dp)
|
||||
print(dp[bagWeight])
|
||||
|
||||
|
||||
test_1_wei_bag_problem()
|
||||
```
|
||||
有参版
|
||||
```python
|
||||
def test_1_wei_bag_problem(weight, value, bagWeight):
|
||||
# 初始化
|
||||
dp = [0] * (bagWeight + 1)
|
||||
for i in range(len(weight)): # 遍历物品
|
||||
for j in range(bagWeight, weight[i] - 1, -1): # 遍历背包容量
|
||||
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
|
||||
|
||||
return dp[bagWeight]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
bagweight = 4
|
||||
|
||||
result = test_1_wei_bag_problem(weight, value, bagweight)
|
||||
print(result)
|
||||
|
||||
```
|
||||
### Go
|
||||
```go
|
||||
func test_1_wei_bag_problem(weight, value []int, bagWeight int) int {
|
||||
|
|
|
|||
|
|
@ -194,55 +194,127 @@ public void testMultiPack2(){
|
|||
|
||||
Python:
|
||||
|
||||
改变物品数量为01背包格式(无参版)
|
||||
```python
|
||||
def test_multi_pack1():
|
||||
'''版本一:改变物品数量为01背包格式'''
|
||||
def test_multi_pack():
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
nums = [2, 3, 2]
|
||||
bag_weight = 10
|
||||
bagWeight = 10
|
||||
|
||||
# 将数量大于1的物品展开
|
||||
for i in range(len(nums)):
|
||||
# 将物品展开数量为1
|
||||
while nums[i] > 1:
|
||||
weight.append(weight[i])
|
||||
value.append(value[i])
|
||||
nums[i] -= 1
|
||||
|
||||
dp = [0]*(bag_weight + 1)
|
||||
# 遍历物品
|
||||
for i in range(len(weight)):
|
||||
# 遍历背包
|
||||
for j in range(bag_weight, weight[i] - 1, -1):
|
||||
|
||||
dp = [0] * (bagWeight + 1)
|
||||
for i in range(len(weight)): # 遍历物品
|
||||
for j in range(bagWeight, weight[i] - 1, -1): # 遍历背包容量
|
||||
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
|
||||
|
||||
print(" ".join(map(str, dp)))
|
||||
for j in range(bagWeight + 1):
|
||||
print(dp[j], end=" ")
|
||||
print()
|
||||
|
||||
def test_multi_pack2():
|
||||
'''版本:改变遍历个数'''
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
nums = [2, 3, 2]
|
||||
bag_weight = 10
|
||||
|
||||
dp = [0]*(bag_weight + 1)
|
||||
for i in range(len(weight)):
|
||||
for j in range(bag_weight, weight[i] - 1, -1):
|
||||
# 以上是01背包,加上遍历个数
|
||||
for k in range(1, nums[i] + 1):
|
||||
if j - k*weight[i] >= 0:
|
||||
dp[j] = max(dp[j], dp[j - k*weight[i]] + k*value[i])
|
||||
|
||||
print(" ".join(map(str, dp)))
|
||||
print(dp[bagWeight])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_multi_pack1()
|
||||
test_multi_pack2()
|
||||
test_multi_pack()
|
||||
|
||||
```
|
||||
|
||||
|
||||
改变遍历个数(无参版)
|
||||
```python
|
||||
def test_multi_pack():
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
nums = [2, 3, 2]
|
||||
bagWeight = 10
|
||||
dp = [0] * (bagWeight + 1)
|
||||
|
||||
for i in range(len(weight)): # 遍历物品
|
||||
for j in range(bagWeight, weight[i] - 1, -1): # 遍历背包容量
|
||||
# 以上为01背包,然后加一个遍历个数
|
||||
for k in range(1, nums[i] + 1): # 遍历个数
|
||||
if j - k * weight[i] >= 0:
|
||||
dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i])
|
||||
|
||||
# 打印一下dp数组
|
||||
for j in range(bagWeight + 1):
|
||||
print(dp[j], end=" ")
|
||||
print()
|
||||
|
||||
print(dp[bagWeight])
|
||||
|
||||
|
||||
test_multi_pack()
|
||||
|
||||
```
|
||||
|
||||
|
||||
改变物品数量为01背包格式(有参版)
|
||||
```python
|
||||
def test_multi_pack(weight, value, nums, bagWeight):
|
||||
# 将数量大于1的物品展开
|
||||
for i in range(len(nums)):
|
||||
while nums[i] > 1:
|
||||
weight.append(weight[i])
|
||||
value.append(value[i])
|
||||
nums[i] -= 1
|
||||
|
||||
dp = [0] * (bagWeight + 1)
|
||||
for i in range(len(weight)): # 遍历物品
|
||||
for j in range(bagWeight, weight[i] - 1, -1): # 遍历背包容量
|
||||
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
|
||||
for j in range(bagWeight + 1):
|
||||
print(dp[j], end=" ")
|
||||
print()
|
||||
|
||||
print(dp[bagWeight])
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
nums = [2, 3, 2]
|
||||
bagWeight = 10
|
||||
test_multi_pack(weight, value, nums, bagWeight)
|
||||
```
|
||||
|
||||
|
||||
改变遍历个数(有参版)
|
||||
```python
|
||||
def test_multi_pack(weight, value, nums, bagWeight):
|
||||
dp = [0] * (bagWeight + 1)
|
||||
|
||||
for i in range(len(weight)): # 遍历物品
|
||||
for j in range(bagWeight, weight[i] - 1, -1): # 遍历背包容量
|
||||
# 以上为01背包,然后加一个遍历个数
|
||||
for k in range(1, nums[i] + 1): # 遍历个数
|
||||
if j - k * weight[i] >= 0:
|
||||
dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i])
|
||||
|
||||
# 使用 join 函数打印 dp 数组
|
||||
print(' '.join(str(dp[j]) for j in range(bagWeight + 1)))
|
||||
|
||||
print(dp[bagWeight])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
nums = [2, 3, 2]
|
||||
bagWeight = 10
|
||||
test_multi_pack(weight, value, nums, bagWeight)
|
||||
|
||||
```
|
||||
Go:
|
||||
|
||||
```go
|
||||
|
|
|
|||
|
|
@ -223,43 +223,81 @@ private static void testCompletePackAnotherWay(){
|
|||
|
||||
Python:
|
||||
|
||||
|
||||
|
||||
先遍历物品,再遍历背包(无参版)
|
||||
```python
|
||||
# 先遍历物品,再遍历背包
|
||||
def test_complete_pack1():
|
||||
def test_CompletePack():
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
bag_weight = 4
|
||||
|
||||
dp = [0]*(bag_weight + 1)
|
||||
|
||||
for i in range(len(weight)):
|
||||
for j in range(weight[i], bag_weight + 1):
|
||||
bagWeight = 4
|
||||
dp = [0] * (bagWeight + 1)
|
||||
for i in range(len(weight)): # 遍历物品
|
||||
for j in range(weight[i], bagWeight + 1): # 遍历背包容量
|
||||
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
|
||||
|
||||
print(dp[bag_weight])
|
||||
print(dp[bagWeight])
|
||||
|
||||
# 先遍历背包,再遍历物品
|
||||
def test_complete_pack2():
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
bag_weight = 4
|
||||
test_CompletePack()
|
||||
|
||||
dp = [0]*(bag_weight + 1)
|
||||
|
||||
for j in range(bag_weight + 1):
|
||||
for i in range(len(weight)):
|
||||
if j >= weight[i]: dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
|
||||
|
||||
print(dp[bag_weight])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_complete_pack1()
|
||||
test_complete_pack2()
|
||||
```
|
||||
|
||||
先遍历物品,再遍历背包(有参版)
|
||||
```python
|
||||
def test_CompletePack(weight, value, bagWeight):
|
||||
dp = [0] * (bagWeight + 1)
|
||||
for i in range(len(weight)): # 遍历物品
|
||||
for j in range(weight[i], bagWeight + 1): # 遍历背包容量
|
||||
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
|
||||
return dp[bagWeight]
|
||||
|
||||
if __name__ == "__main__":
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
bagWeight = 4
|
||||
result = test_CompletePack(weight, value, bagWeight)
|
||||
print(result)
|
||||
|
||||
```
|
||||
先遍历背包,再遍历物品(无参版)
|
||||
```python
|
||||
def test_CompletePack():
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
bagWeight = 4
|
||||
|
||||
dp = [0] * (bagWeight + 1)
|
||||
|
||||
for j in range(bagWeight + 1): # 遍历背包容量
|
||||
for i in range(len(weight)): # 遍历物品
|
||||
if j - weight[i] >= 0:
|
||||
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
|
||||
|
||||
print(dp[bagWeight])
|
||||
|
||||
test_CompletePack()
|
||||
|
||||
|
||||
```
|
||||
|
||||
先遍历背包,再遍历物品(有参版)
|
||||
```python
|
||||
def test_CompletePack(weight, value, bagWeight):
|
||||
dp = [0] * (bagWeight + 1)
|
||||
for j in range(bagWeight + 1): # 遍历背包容量
|
||||
for i in range(len(weight)): # 遍历物品
|
||||
if j - weight[i] >= 0:
|
||||
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
|
||||
return dp[bagWeight]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
weight = [1, 3, 4]
|
||||
value = [15, 20, 30]
|
||||
bagWeight = 4
|
||||
result = test_CompletePack(weight, value, bagWeight)
|
||||
print(result)
|
||||
|
||||
```
|
||||
|
||||
Go:
|
||||
```go
|
||||
|
|
|
|||
Loading…
Reference in New Issue