Merge branch 'youngyangyang04:master' into master

This commit is contained in:
fwqaaq
2023-05-27 15:34:07 +08:00
committed by GitHub
95 changed files with 3558 additions and 1963 deletions

View File

@ -41,7 +41,7 @@
那么我们就应该想到使用哈希法了。
因为本地,我们不仅要知道元素有没有遍历过,还知道这个元素对应的下标,**需要使用 key value结构来存放key来存元素value来存下标那么使用map正合适**。
因为本地,我们不仅要知道元素有没有遍历过,还知道这个元素对应的下标,**需要使用 key value结构来存放key来存元素value来存下标那么使用map正合适**。
再来看一下使用数组和set来做哈希法的局限。
@ -151,7 +151,7 @@ public int[] twoSum(int[] nums, int target) {
```
Python
(版本一) 使用字典
```python
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
@ -163,6 +163,53 @@ class Solution:
records[value] = index # 遍历当前元素并在map中寻找是否有匹配的key
return []
```
(版本二)使用集合
```python
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
#创建一个集合来存储我们目前看到的数字
seen = set()
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [nums.index(complement), i]
seen.add(num)
```
(版本三)使用双指针
```python
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
# 对输入列表进行排序
nums_sorted = sorted(nums)
# 使用双指针
left = 0
right = len(nums_sorted) - 1
while left < right:
current_sum = nums_sorted[left] + nums_sorted[right]
if current_sum == target:
# 如果和等于目标数,则返回两个数的下标
left_index = nums.index(nums_sorted[left])
right_index = nums.index(nums_sorted[right])
if left_index == right_index:
right_index = nums[left_index+1:].index(nums_sorted[right]) + left_index + 1
return [left_index, right_index]
elif current_sum < target:
# 如果总和小于目标,则将左侧指针向右移动
left += 1
else:
# 如果总和大于目标值,则将右指针向左移动
right -= 1
```
(版本四)暴力法
```python
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
for i in range(len(nums)):
for j in range(i+1, len(nums)):
if nums[i] + nums[j] == target:
return [i,j]
```
Go

View File

@ -298,61 +298,72 @@ class Solution {
```
Python
(版本一) 双指针
```Python
class Solution:
def threeSum(self, nums):
ans = []
n = len(nums)
def threeSum(self, nums: List[int]) -> List[List[int]]:
result = []
nums.sort()
# 找出a + b + c = 0
# a = nums[i], b = nums[left], c = nums[right]
for i in range(n):
left = i + 1
right = n - 1
# 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
if nums[i] > 0:
break
if i >= 1 and nums[i] == nums[i - 1]: # 去重a
for i in range(len(nums)):
# 如果第一个元素已经大于0不需要进一步检查
if nums[i] > 0:
return result
# 跳过相同的元素以避免重复
if i > 0 and nums[i] == nums[i - 1]:
continue
while left < right:
total = nums[i] + nums[left] + nums[right]
if total > 0:
right -= 1
elif total < 0:
left = i + 1
right = len(nums) - 1
while right > left:
sum_ = nums[i] + nums[left] + nums[right]
if sum_ < 0:
left += 1
elif sum_ > 0:
right -= 1
else:
ans.append([nums[i], nums[left], nums[right]])
# 去重逻辑应该放在找到一个三元组之后对b 和 c去重
while left != right and nums[left] == nums[left + 1]: left += 1
while left != right and nums[right] == nums[right - 1]: right -= 1
left += 1
result.append([nums[i], nums[left], nums[right]])
# 跳过相同的元素以避免重复
while right > left and nums[right] == nums[right - 1]:
right -= 1
while right > left and nums[left] == nums[left + 1]:
left += 1
right -= 1
return ans
left += 1
return result
```
Python (v3):
(版本二) 使用字典
```python
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
if len(nums) < 3: return []
nums, res = sorted(nums), []
for i in range(len(nums) - 2):
cur, l, r = nums[i], i + 1, len(nums) - 1
if res != [] and res[-1][0] == cur: continue # Drop duplicates for the first time.
while l < r:
if cur + nums[l] + nums[r] == 0:
res.append([cur, nums[l], nums[r]])
# Drop duplicates for the second time in interation of l & r. Only used when target situation occurs, because that is the reason for dropping duplicates.
while l < r - 1 and nums[l] == nums[l + 1]:
l += 1
while r > l + 1 and nums[r] == nums[r - 1]:
r -= 1
if cur + nums[l] + nums[r] > 0:
r -= 1
result = []
nums.sort()
# 找出a + b + c = 0
# a = nums[i], b = nums[j], c = -(a + b)
for i in range(len(nums)):
# 排序之后如果第一个元素已经大于零,那么不可能凑成三元组
if nums[i] > 0:
break
if i > 0 and nums[i] == nums[i - 1]: #三元组元素a去重
continue
d = {}
for j in range(i + 1, len(nums)):
if j > i + 2 and nums[j] == nums[j-1] == nums[j-2]: # 三元组元素b去重
continue
c = 0 - (nums[i] + nums[j])
if c in d:
result.append([nums[i], nums[j], c])
d.pop(c) # 三元组元素c去重
else:
l += 1
return res
d[nums[j]] = j
return result
```
Go

View File

@ -183,6 +183,8 @@ public:
}
};
```
* 时间复杂度: O(3^m * 4^n),其中 m 是对应四个字母的数字个数n 是对应三个字母的数字个数
* 空间复杂度: O(3^m * 4^n)
一些写法,是把回溯的过程放在递归函数里了,例如如下代码,我可以写成这样:(注意注释中不一样的地方)

View File

@ -207,35 +207,44 @@ class Solution {
```
Python
(版本一) 双指针
```python
# 双指针法
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
n = len(nums)
res = []
for i in range(n):
if i > 0 and nums[i] == nums[i - 1]: continue # 对nums[i]去重
for k in range(i+1, n):
if k > i + 1 and nums[k] == nums[k-1]: continue # 对nums[k]去重
p = k + 1
q = n - 1
while p < q:
if nums[i] + nums[k] + nums[p] + nums[q] > target: q -= 1
elif nums[i] + nums[k] + nums[p] + nums[q] < target: p += 1
result = []
for i in range(n):
if nums[i] > target and nums[i] > 0 and target > 0:# 剪枝(可省)
break
if i > 0 and nums[i] == nums[i-1]:# 去重
continue
for j in range(i+1, n):
if nums[i] + nums[j] > target and target > 0: #剪枝(可省)
break
if j > i+1 and nums[j] == nums[j-1]: # 去重
continue
left, right = j+1, n-1
while left < right:
s = nums[i] + nums[j] + nums[left] + nums[right]
if s == target:
result.append([nums[i], nums[j], nums[left], nums[right]])
while left < right and nums[left] == nums[left+1]:
left += 1
while left < right and nums[right] == nums[right-1]:
right -= 1
left += 1
right -= 1
elif s < target:
left += 1
else:
res.append([nums[i], nums[k], nums[p], nums[q]])
# 对nums[p]和nums[q]去重
while p < q and nums[p] == nums[p + 1]: p += 1
while p < q and nums[q] == nums[q - 1]: q -= 1
p += 1
q -= 1
return res
right -= 1
return result
```
(版本二) 使用字典
```python
# 哈希表法
class Solution(object):
def fourSum(self, nums, target):
"""
@ -243,36 +252,25 @@ class Solution(object):
:type target: int
:rtype: List[List[int]]
"""
# use a dict to store value:showtimes
hashmap = dict()
for n in nums:
if n in hashmap:
hashmap[n] += 1
else:
hashmap[n] = 1
# 创建一个字典来存储输入列表中每个数字的频率
freq = {}
for num in nums:
freq[num] = freq.get(num, 0) + 1
# good thing about using python is you can use set to drop duplicates.
# 创建一个集合来存储最终答案并遍历4个数字的所有唯一组合
ans = set()
# ans = [] # save results by list()
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
for k in range(j + 1, len(nums)):
val = target - (nums[i] + nums[j] + nums[k])
if val in hashmap:
# make sure no duplicates.
if val in freq:
# 确保没有重复
count = (nums[i] == val) + (nums[j] == val) + (nums[k] == val)
if hashmap[val] > count:
ans_tmp = tuple(sorted([nums[i], nums[j], nums[k], val]))
ans.add(ans_tmp)
# Avoiding duplication in list manner but it cause time complexity increases
# if ans_tmp not in ans:
# ans.append(ans_tmp)
else:
continue
return list(ans)
# if used list() to save results, just
# return ans
if freq[val] > count:
ans.add(tuple(sorted([nums[i], nums[j], nums[k], val])))
return [list(x) for x in ans]
```
Go

View File

@ -127,21 +127,29 @@ Python:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
head_dummy = ListNode()
head_dummy.next = head
slow, fast = head_dummy, head_dummy
while(n>=0): #fast先往前走n+1步
# 创建一个虚拟节点,并将其下一个指针设置为链表的头部
dummy_head = ListNode(0, head)
# 创建两个指针,慢指针和快指针,并将它们初始化为虚拟节点
slow = fast = dummy_head
# 快指针比慢指针快 n+1 步
for i in range(n+1):
fast = fast.next
n -= 1
while(fast!=None):
# 移动两个指针,直到快速指针到达链表的末尾
while fast:
slow = slow.next
fast = fast.next
#fast 走到结尾后slow的下一个节点为倒数第N个节点
slow.next = slow.next.next #删除
return head_dummy.next
# 通过更新第 (n-1) 个节点的 next 指针删除第 n 个节点
slow.next = slow.next.next
return dummy_head.next
```
Go:
```Go

View File

@ -186,21 +186,20 @@ Python
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
res = ListNode(next=head)
pre = res
dummy_head = ListNode(next=head)
current = dummy_head
# 必须有pre的下一个和下下个才能交换,否则说明已经交换结束了
while pre.next and pre.next.next:
cur = pre.next
post = pre.next.next
# 必须有cur的下一个和下下个才能交换,否则说明已经交换结束了
while current.next and current.next.next:
temp = current.next # 防止节点修改
temp1 = current.next.next.next
# precurpost对应最左中间的最右边的节点
cur.next = post.next
post.next = cur
pre.next = post
current.next = current.next.next
current.next.next = temp
temp.next = temp1
current = current.next.next
return dummy_head.next
pre = pre.next.next
return res.next
```
Go

View File

@ -198,6 +198,7 @@ Python
``` python 3
(版本一)快慢指针法
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
# 快慢指针
@ -213,7 +214,21 @@ class Solution:
return slow
```
``` python 3
(版本二)暴力法
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
i, l = 0, len(nums)
while i < l:
if nums[i] == val: # 找到等于目标值的节点
for j in range(i+1, l): # 移除该元素,并将后面元素向前平移
nums[j - 1] = nums[j]
l -= 1
i -= 1
i += 1
return l
```
Go

View File

@ -692,8 +692,67 @@ class Solution {
```
Python3
(版本一)前缀表(减一)
```python
class Solution:
def getNext(self, next, s):
j = -1
next[0] = j
for i in range(1, len(s)):
while j >= 0 and s[i] != s[j+1]:
j = next[j]
if s[i] == s[j+1]:
j += 1
next[i] = j
def strStr(self, haystack: str, needle: str) -> int:
if not needle:
return 0
next = [0] * len(needle)
self.getNext(next, needle)
j = -1
for i in range(len(haystack)):
while j >= 0 and haystack[i] != needle[j+1]:
j = next[j]
if haystack[i] == needle[j+1]:
j += 1
if j == len(needle) - 1:
return i - len(needle) + 1
return -1
```
(版本二)前缀表(不减一)
```python
class Solution:
def getNext(self, next: List[int], s: str) -> None:
j = 0
next[0] = 0
for i in range(1, len(s)):
while j > 0 and s[i] != s[j]:
j = next[j - 1]
if s[i] == s[j]:
j += 1
next[i] = j
def strStr(self, haystack: str, needle: str) -> int:
if len(needle) == 0:
return 0
next = [0] * len(needle)
self.getNext(next, needle)
j = 0
for i in range(len(haystack)):
while j > 0 and haystack[i] != needle[j]:
j = next[j - 1]
if haystack[i] == needle[j]:
j += 1
if j == len(needle):
return i - len(needle) + 1
return -1
```
(版本三)暴力法
```python
//暴力解法
class Solution(object):
def strStr(self, haystack, needle):
"""
@ -707,102 +766,22 @@ class Solution(object):
return i
return -1
```
(版本四)使用 index
```python
// 方法一
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
a = len(needle)
b = len(haystack)
if a == 0:
return 0
next = self.getnext(a,needle)
p=-1
for j in range(b):
while p >= 0 and needle[p+1] != haystack[j]:
p = next[p]
if needle[p+1] == haystack[j]:
p += 1
if p == a-1:
return j-a+1
return -1
def getnext(self,a,needle):
next = ['' for i in range(a)]
k = -1
next[0] = k
for i in range(1, len(needle)):
while (k > -1 and needle[k+1] != needle[i]):
k = next[k]
if needle[k+1] == needle[i]:
k += 1
next[i] = k
return next
```
```python
// 方法二
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
a = len(needle)
b = len(haystack)
if a == 0:
return 0
i = j = 0
next = self.getnext(a, needle)
while(i < b and j < a):
if j == -1 or needle[j] == haystack[i]:
i += 1
j += 1
else:
j = next[j]
if j == a:
return i-j
else:
try:
return haystack.index(needle)
except ValueError:
return -1
def getnext(self, a, needle):
next = ['' for i in range(a)]
j, k = 0, -1
next[0] = k
while(j < a-1):
if k == -1 or needle[k] == needle[j]:
k += 1
j += 1
next[j] = k
else:
k = next[k]
return next
```
(版本五)使用 find
```python
// 前缀表不减一Python实现
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
if len(needle) == 0:
return 0
next = self.getNext(needle)
j = 0
for i in range(len(haystack)):
while j >= 1 and haystack[i] != needle[j]:
j = next[j-1]
if haystack[i] == needle[j]:
j += 1
if j == len(needle):
return i - len(needle) + 1
return -1
def getNext(self, needle):
next = [0] * len(needle)
j = 0
next[0] = j
for i in range(1, len(needle)):
while j >= 1 and needle[i] != needle[j]:
j = next[j-1]
if needle[i] == needle[j]:
j += 1
next[i] = j
return next
```
return haystack.find(needle)
```
Go
@ -1314,7 +1293,6 @@ impl Solution {
pub fn str_str(haystack: String, needle: String) -> i32 {
let (haystack_len, needle_len) = (haystack.len(), needle.len());
if haystack_len == 0 { return 0; }
if haystack_len < needle_len { return -1;}
let (haystack, needle) = (haystack.chars().collect::<Vec<char>>(), needle.chars().collect::<Vec<char>>());
let mut next: Vec<usize> = vec![0; haystack_len];
@ -1355,9 +1333,6 @@ impl Solution {
next
}
pub fn str_str(haystack: String, needle: String) -> i32 {
if needle.is_empty() {
return 0;
}
if haystack.len() < needle.len() {
return -1;
}

View File

@ -191,8 +191,8 @@ public:
};
```
* 时间复杂度:$O(\log n)$
* 间复杂度:$O(1)$
* 时间复杂度O(log n)
* 间复杂度O(1)
## 总结
@ -274,7 +274,7 @@ func searchInsert(nums []int, target int) int {
left = mid + 1
}
}
return len(nums)
return right+1
}
```

View File

@ -214,6 +214,8 @@ public:
}
};
```
* 时间复杂度: O(n * 2^n),注意这只是复杂度的上界,因为剪枝的存在,真实的时间复杂度远小于此
* 空间复杂度: O(target)
# 总结

View File

@ -214,6 +214,8 @@ public:
};
```
* 时间复杂度: O(n * 2^n)
* 空间复杂度: O(n)
## 补充

View File

@ -136,6 +136,8 @@ public:
}
};
```
* 时间复杂度: O(n!)
* 空间复杂度: O(n)
## 总结

View File

@ -99,6 +99,8 @@ public:
};
```
* 时间复杂度: O(n)
* 空间复杂度: O(n)
## 拓展

View File

@ -208,6 +208,9 @@ public:
}
};
```
* 时间复杂度: O(n!)
* 空间复杂度: O(n)
可以看出,除了验证棋盘合法性的代码,省下来部分就是按照回溯法模板来的。

View File

@ -124,7 +124,7 @@ public:
## 动态规划
当然本题还可以用动态规划来做,当前[「代码随想录」](https://img-blog.csdnimg.cn/20201124161234338.png)主要讲解贪心系列,后续到动态规划系列的时候会详细讲解本题的 dp 方法。
当然本题还可以用动态规划来做,在代码随想录动态规划章节我会详细介绍,如果大家想在想看,可以直接跳转:[动态规划版本详解](https://programmercarl.com/0053.%E6%9C%80%E5%A4%A7%E5%AD%90%E5%BA%8F%E5%92%8C%EF%BC%88%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%EF%BC%89.html#%E6%80%9D%E8%B7%AF)
那么先给出我的 dp 代码如下,有时间的录友可以提前做一做:

View File

@ -493,6 +493,33 @@ impl Solution {
}
```
空间优化:
```rust
impl Solution {
pub fn unique_paths_with_obstacles(obstacle_grid: Vec<Vec<i32>>) -> i32 {
let mut dp = vec![0; obstacle_grid[0].len()];
for (i, &v) in obstacle_grid[0].iter().enumerate() {
if v == 0 {
dp[i] = 1;
} else {
break;
}
}
for rows in obstacle_grid.iter().skip(1) {
for j in 0..rows.len() {
if rows[j] == 1 {
dp[j] = 0;
} else if j != 0 {
dp[j] += dp[j - 1];
}
}
}
dp.pop().unwrap()
}
}
```
### C
```c

View File

@ -218,6 +218,10 @@ public:
}
};
```
* 时间复杂度: O(n * 2^n)
* 空间复杂度: O(n)
还记得我们在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中给出的回溯法模板么?

View File

@ -130,6 +130,10 @@ public:
}
};
```
* 时间复杂度: O(n * 2^n)
* 空间复杂度: O(n)
# 总结

View File

@ -149,6 +149,8 @@ public:
};
```
* 时间复杂度: O(n * 2^n)
* 空间复杂度: O(n)
在注释中,可以发现可以不写终止条件,因为本来我们就要遍历整棵树。

View File

@ -307,6 +307,33 @@ class Solution {
}
}
```
单调栈精简
```java
class Solution {
public int largestRectangleArea(int[] heights) {
int[] newHeight = new int[heights.length + 2];
System.arraycopy(heights, 0, newHeight, 1, heights.length);
newHeight[heights.length+1] = 0;
newHeight[0] = 0;
Stack<Integer> stack = new Stack<>();
stack.push(0);
int res = 0;
for (int i = 1; i < newHeight.length; i++) {
while (newHeight[i] < newHeight[stack.peek()]) {
int mid = stack.pop();
int w = i - stack.peek() - 1;
int h = newHeight[mid];
res = Math.max(res, w * h);
}
stack.push(i);
}
return res;
}
}
```
Python3:

View File

@ -83,6 +83,9 @@ public:
}
};
```
* 时间复杂度: O(n * 2^n)
* 空间复杂度: O(n)
使用set去重的版本。
```CPP

View File

@ -244,6 +244,8 @@ public:
};
```
* 时间复杂度: O(3^4)IP地址最多包含4个数字每个数字最多有3种可能的分割方式则搜索树的最大深度为4每个节点最多有3个子节点。
* 空间复杂度: O(n)
# 总结

View File

@ -259,6 +259,36 @@ public:
## Java
```Java
//使用統一迭代法
class Solution {
public boolean isValidBST(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode pre = null;
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 && pre.val >= temp.val)
return false;
pre = temp;
}
}
return true;
}
}
```
```Java
class Solution {
// 递归
@ -341,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

View File

@ -88,7 +88,7 @@ else if (left->val != right->val) return false; // 注意这里我没有
* 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
* 比较内是否对称,传入左节点的右孩子,右节点的左孩子。
* 比较内是否对称,传入左节点的右孩子,右节点的左孩子。
* 如果左右都对称就返回true 有一侧不对称就返回false 。
代码如下:
@ -157,7 +157,7 @@ public:
**这个代码就很简洁了,但隐藏了很多逻辑,条理不清晰,而且递归三部曲,在这里完全体现不出来。**
**所以建议大家做题的时候,一定要想清楚逻辑,每一步做什么。把题目所有情况想到位,相应的代码写出来之后,再去追求简洁代码的效果。**
**所以建议大家做题的时候,一定要想清楚逻辑,每一步做什么。把题目所有情况想到位,相应的代码写出来之后,再去追求简洁代码的效果。**
## 迭代法
@ -442,25 +442,31 @@ class Solution:
层次遍历
```python
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
que = [root]
while que:
this_level_length = len(que)
for i in range(this_level_length // 2):
# 要么其中一个是None但另外一个不是
if (not que[i] and que[this_level_length - 1 - i]) or (que[i] and not que[this_level_length - 1 - i]):
return False
# 要么两个都不是None
if que[i] and que[i].val != que[this_level_length - 1 - i].val:
return False
for i in range(this_level_length):
if not que[i]: continue
que.append(que[i].left)
que.append(que[i].right)
que = que[this_level_length:]
queue = collections.deque([root.left, root.right])
while queue:
level_size = len(queue)
if level_size % 2 != 0:
return False
level_vals = []
for i in range(level_size):
node = queue.popleft()
if node:
level_vals.append(node.val)
queue.append(node.left)
queue.append(node.right)
else:
level_vals.append(None)
if level_vals != level_vals[::-1]:
return False
return True
```

View File

@ -171,47 +171,59 @@ python3代码
```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 levelOrder(self, root: TreeNode) -> List[List[int]]:
results = []
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if not root:
return results
from collections import deque
que = deque([root])
while que:
size = len(que)
result = []
for _ in range(size):
cur = que.popleft()
result.append(cur.val)
return []
queue = collections.deque([root])
result = []
while queue:
level = []
for _ in range(len(queue)):
cur = queue.popleft()
level.append(cur.val)
if cur.left:
que.append(cur.left)
queue.append(cur.left)
if cur.right:
que.append(cur.right)
results.append(result)
return results
queue.append(cur.right)
result.append(level)
return result
```
```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 levelOrder(self, root: TreeNode) -> List[List[int]]:
res = []
def helper(root, depth):
if not root: return []
if len(res) == depth: res.append([]) # start the current depth
res[depth].append(root.val) # fulfil the current depth
if root.left: helper(root.left, depth + 1) # process child nodes for the next depth
if root.right: helper(root.right, depth + 1)
helper(root, 0)
return res
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
levels = []
self.helper(root, 0, levels)
return levels
def helper(self, node, level, levels):
if not node:
return
if len(levels) == level:
levels.append([])
levels[level].append(node.val)
self.helper(node.left, level + 1, levels)
self.helper(node.right, level + 1, levels)
```
go:
```go
@ -500,27 +512,29 @@ python代码
class Solution:
"""二叉树层序遍历II迭代解法"""
# 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 levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
results = []
if not root:
return results
from collections import deque
que = deque([root])
while que:
result = []
for _ in range(len(que)):
cur = que.popleft()
result.append(cur.val)
return []
queue = collections.deque([root])
result = []
while queue:
level = []
for _ in range(len(queue)):
cur = queue.popleft()
level.append(cur.val)
if cur.left:
que.append(cur.left)
queue.append(cur.left)
if cur.right:
que.append(cur.right)
results.append(result)
results.reverse()
return results
queue.append(cur.right)
result.append(level)
return result[::-1]
```
Java
@ -821,35 +835,35 @@ public:
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 rightSideView(self, root: TreeNode) -> List[int]:
if not root:
return []
# deque来自collections模块不在力扣平台时需要手动写入
# 'from collections import deque' 导入
# deque相比list的好处是list的pop(0)是O(n)复杂度deque的popleft()是O(1)复杂度
quene = deque([root])
out_list = []
while quene:
# 每次都取最后一个node就可以了
node = quene[-1]
out_list.append(node.val)
# 执行这个遍历的目的是获取下一层所有的node
for _ in range(len(quene)):
node = quene.popleft()
queue = collections.deque([root])
right_view = []
while queue:
level_size = len(queue)
for i in range(level_size):
node = queue.popleft()
if i == level_size - 1:
right_view.append(node.val)
if node.left:
quene.append(node.left)
queue.append(node.left)
if node.right:
quene.append(node.right)
return out_list
# 执行用时36 ms, 在所有 Python3 提交中击败了89.47%的用户
# 内存消耗14.6 MB, 在所有 Python3 提交中击败了96.65%的用户
queue.append(node.right)
return right_view
```
@ -1107,27 +1121,38 @@ python代码
class Solution:
"""二叉树层平均值迭代解法"""
# 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 averageOfLevels(self, root: TreeNode) -> List[float]:
results = []
if not root:
return results
return []
from collections import deque
que = deque([root])
while que:
size = len(que)
sum_ = 0
for _ in range(size):
cur = que.popleft()
sum_ += cur.val
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
results.append(sum_ / size)
return results
queue = collections.deque([root])
averages = []
while queue:
size = len(queue)
level_sum = 0
for i in range(size):
node = queue.popleft()
level_sum += node.val
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
averages.append(level_sum / size)
return averages
```
java:
@ -1401,28 +1426,36 @@ public:
python代码
```python
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
"""N叉树的层序遍历迭代法"""
def levelOrder(self, root: 'Node') -> List[List[int]]:
results = []
if not root:
return results
return []
from collections import deque
que = deque([root])
result = []
queue = collections.deque([root])
while que:
result = []
for _ in range(len(que)):
cur = que.popleft()
result.append(cur.val)
# cur.children 是 Node 对象组成的列表,也可能为 None
if cur.children:
que.extend(cur.children)
results.append(result)
while queue:
level_size = len(queue)
level = []
return results
for _ in range(level_size):
node = queue.popleft()
level.append(node.val)
for child in node.children:
queue.append(child)
result.append(level)
return result
```
```python
@ -1728,22 +1761,37 @@ public:
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 largestValues(self, root: TreeNode) -> List[int]:
if root is None:
if not root:
return []
queue = [root]
out_list = []
result = []
queue = collections.deque([root])
while queue:
length = len(queue)
in_list = []
for _ in range(length):
curnode = queue.pop(0)
in_list.append(curnode.val)
if curnode.left: queue.append(curnode.left)
if curnode.right: queue.append(curnode.right)
out_list.append(max(in_list))
return out_list
level_size = len(queue)
max_val = float('-inf')
for _ in range(level_size):
node = queue.popleft()
max_val = max(max_val, node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.append(max_val)
return result
```
java代码
@ -2048,36 +2096,40 @@ class Solution {
python代码
```python
# 层序遍历解法
"""
# Definition for a Node.
class Node:
def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root:
return None
queue = [root]
return root
queue = collections.deque([root])
while queue:
n = len(queue)
for i in range(n):
node = queue.pop(0)
level_size = len(queue)
prev = None
for i in range(level_size):
node = queue.popleft()
if prev:
prev.next = node
prev = node
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
if i == n - 1:
break
node.next = queue[0]
return root
# 链表解法
class Solution:
def connect(self, root: 'Node') -> 'Node':
first = root
while first:
cur = first
while cur: # 遍历每一层的节点
if cur.left: cur.left.next = cur.right # 找左节点的next
if cur.right and cur.next: cur.right.next = cur.next.left # 找右节点的next
cur = cur.next # cur同层移动到下一节点
first = first.left # 从本层扩展到下一层
return root
```
@ -2329,21 +2381,41 @@ python代码
```python
# 层序遍历解法
"""
# Definition for a Node.
class Node:
def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root:
return None
queue = [root]
while queue: # 遍历每一层
length = len(queue)
tail = None # 每一层维护一个尾节点
for i in range(length): # 遍历当前层
curnode = queue.pop(0)
if tail:
tail.next = curnode # 让尾节点指向当前节点
tail = curnode # 让当前节点成为尾节点
if curnode.left : queue.append(curnode.left)
if curnode.right: queue.append(curnode.right)
return root
queue = collections.deque([root])
while queue:
level_size = len(queue)
prev = None
for i in range(level_size):
node = queue.popleft()
if prev:
prev.next = node
prev = node
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return root
```
@ -2592,24 +2664,31 @@ class Solution {
Python
```python 3
# 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 maxDepth(self, root: TreeNode) -> int:
if root == None:
if not root:
return 0
queue_ = [root]
depth = 0
while queue_:
length = len(queue_)
for i in range(length):
cur = queue_.pop(0)
sub.append(cur.val)
#子节点入队列
if cur.left: queue_.append(cur.left)
if cur.right: queue_.append(cur.right)
queue = collections.deque([root])
while queue:
depth += 1
for _ in range(len(queue)):
node = queue.popleft()
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return depth
```
Go
@ -2859,23 +2938,26 @@ Python 3
# self.right = right
class Solution:
def minDepth(self, root: TreeNode) -> int:
if root == None:
if not root:
return 0
depth = 0
queue = collections.deque([root])
while queue:
depth += 1
for _ in range(len(queue)):
node = queue.popleft()
if not node.left and not node.right:
return depth
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
#根节点的深度为1
queue_ = [(root,1)]
while queue_:
cur, depth = queue_.pop(0)
if cur.left == None and cur.right == None:
return depth
#先左子节点,由于左子节点没有孩子,则就是这一层了
if cur.left:
queue_.append((cur.left,depth + 1))
if cur.right:
queue_.append((cur.right,depth + 1))
return 0
return depth
```
Go

View File

@ -419,86 +419,107 @@ class solution:
return 1 + max(self.maxdepth(root.left), self.maxdepth(root.right))
```
迭代法:
层序遍历迭代法:
```python
import collections
class solution:
def maxdepth(self, root: treenode) -> int:
# 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 maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
depth = 0 #记录深度
queue = collections.deque()
queue.append(root)
depth = 0
queue = collections.deque([root])
while queue:
size = len(queue)
depth += 1
for i in range(size):
for _ in range(len(queue)):
node = queue.popleft()
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return depth
```
### 559.n叉树的最大深度
递归法:
```python
class solution:
def maxdepth(self, root: 'node') -> int:
class Solution:
def maxDepth(self, root: 'Node') -> int:
if not root:
return 0
depth = 0
for i in range(len(root.children)):
depth = max(depth, self.maxdepth(root.children[i]))
return depth + 1
max_depth = 1
for child in root.children:
max_depth = max(max_depth, self.maxDepth(child) + 1)
return max_depth
```
迭代法:
```python
import collections
class solution:
def maxdepth(self, root: 'node') -> int:
queue = collections.deque()
if root:
queue.append(root)
depth = 0 #记录深度
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
depth = 0
queue = collections.deque([root])
while queue:
size = len(queue)
depth += 1
for i in range(size):
for _ in range(len(queue)):
node = queue.popleft()
for j in range(len(node.children)):
if node.children[j]:
queue.append(node.children[j])
for child in node.children:
queue.append(child)
return depth
```
使用栈来模拟后序遍历依然可以
使用栈
```python
class solution:
def maxdepth(self, root: 'node') -> int:
st = []
if root:
st.append(root)
depth = 0
result = 0
while st:
node = st.pop()
if node != none:
st.append(node) #中
st.append(none)
depth += 1
for i in range(len(node.children)): #处理孩子
if node.children[i]:
st.append(node.children[i])
else:
node = st.pop()
depth -= 1
result = max(result, depth)
return result
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def maxDepth(self, root: 'Node') -> int:
if not root:
return 0
max_depth = 0
stack = [(root, 1)]
while stack:
node, depth = stack.pop()
max_depth = max(max_depth, depth)
for child in node.children:
stack.append((child, depth + 1))
return max_depth
```

View File

@ -400,8 +400,6 @@ public:
};
```
## Python
# 105.从前序与中序遍历序列构造二叉树
@ -622,7 +620,42 @@ class Solution {
}
}
```
```java
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if(postorder.length == 0 || inorder.length == 0)
return null;
return buildHelper(inorder, 0, inorder.length, postorder, 0, postorder.length);
}
private TreeNode buildHelper(int[] inorder, int inorderStart, int inorderEnd, int[] postorder, int postorderStart, int postorderEnd){
if(postorderStart == postorderEnd)
return null;
int rootVal = postorder[postorderEnd - 1];
TreeNode root = new TreeNode(rootVal);
int middleIndex;
for (middleIndex = inorderStart; middleIndex < inorderEnd; middleIndex++){
if(inorder[middleIndex] == rootVal)
break;
}
int leftInorderStart = inorderStart;
int leftInorderEnd = middleIndex;
int rightInorderStart = middleIndex + 1;
int rightInorderEnd = inorderEnd;
int leftPostorderStart = postorderStart;
int leftPostorderEnd = postorderStart + (middleIndex - inorderStart);
int rightPostorderStart = leftPostorderEnd;
int rightPostorderEnd = postorderEnd - 1;
root.left = buildHelper(inorder, leftInorderStart, leftInorderEnd, postorder, leftPostorderStart, leftPostorderEnd);
root.right = buildHelper(inorder, rightInorderStart, rightInorderEnd, postorder, rightPostorderStart, rightPostorderEnd);
return root;
}
}
```
105.从前序与中序遍历序列构造二叉树
```java
@ -657,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
@ -717,7 +718,7 @@ class Solution:
# 第六步: 递归
root.left = self.buildTree(preorder_left, inorder_left)
root.right = self.buildTree(preorder_right, inorder_right)
# 第七步: 返回答案
return root
```
@ -749,7 +750,7 @@ class Solution:
# 第六步: 递归
root.left = self.buildTree(inorder_left, postorder_left)
root.right = self.buildTree(inorder_right, postorder_right)
# 第七步: 返回答案
return root
```

View File

@ -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

View File

@ -532,9 +532,71 @@ class Solution:
else:
return 1 + max(left_height, right_height)
```
递归法精简版:
```python
class Solution:
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:
@ -558,8 +620,6 @@ class Solution:
height_map[real_node] = 1 + max(left, right)
return True
```
### Go
```Go

View File

@ -302,50 +302,106 @@ class Solution {
## Python
递归法
递归法(版本一)
```python
class Solution:
def minDepth(self, root: TreeNode) -> int:
if not root:
def getDepth(self, node):
if node is None:
return 0
if not root.left and not root.right:
return 1
leftDepth = self.getDepth(node.left) # 左
rightDepth = self.getDepth(node.right) # 右
# 当一个左子树为空,右不为空,这时并不是最低点
if node.left is None and node.right is not None:
return 1 + rightDepth
# 当一个右子树为空,左不为空,这时并不是最低点
if node.left is not None and node.right is None:
return 1 + leftDepth
result = 1 + min(leftDepth, rightDepth)
return result
def minDepth(self, root):
return self.getDepth(root)
min_depth = 10**9
if root.left:
min_depth = min(self.minDepth(root.left), min_depth) # 获得左子树的最小高度
if root.right:
min_depth = min(self.minDepth(root.right), min_depth) # 获得右子树的最小高度
return min_depth + 1
```
迭代法:
递归法(版本二)
```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.
# 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
que = deque()
que.append(root)
res = 1
while que:
for _ in range(len(que)):
node = que.popleft()
# 当左右孩子都为空的时候,说明是最低点的一层了,退出
depth = 0
queue = collections.deque([root])
while queue:
depth += 1
for _ in range(len(queue)):
node = queue.popleft()
if not node.left and not node.right:
return res
if node.left is not None:
que.append(node.left)
if node.right is not None:
que.append(node.right)
res += 1
return res
return depth
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return depth
```
## Go
```go

View File

@ -385,6 +385,42 @@ class solution {
}
}
```
```Java 統一迭代法
public boolean hasPathSum(TreeNode root, int targetSum) {
Stack<TreeNode> treeNodeStack = new Stack<>();
Stack<Integer> sumStack = new Stack<>();
if(root == null)
return false;
treeNodeStack.add(root);
sumStack.add(root.val);
while(!treeNodeStack.isEmpty()){
TreeNode curr = treeNodeStack.peek();
int tempsum = sumStack.pop();
if(curr != null){
treeNodeStack.pop();
treeNodeStack.add(curr);
treeNodeStack.add(null);
sumStack.add(tempsum);
if(curr.right != null){
treeNodeStack.add(curr.right);
sumStack.add(tempsum + curr.right.val);
}
if(curr.left != null){
treeNodeStack.add(curr.left);
sumStack.add(tempsum + curr.left.val);
}
}else{
treeNodeStack.pop();
TreeNode temp = treeNodeStack.pop();
if(temp.left == null && temp.right == null && tempsum == targetSum)
return true;
}
}
return false;
}
```
### 0113.路径总和-ii
@ -446,145 +482,242 @@ class Solution {
}
}
```
```java
// 解法3 DFS统一迭代法
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> result = new ArrayList<>();
Stack<TreeNode> nodeStack = new Stack<>();
Stack<Integer> sumStack = new Stack<>();
Stack<ArrayList<Integer>> pathStack = new Stack<>();
if(root == null)
return result;
nodeStack.add(root);
sumStack.add(root.val);
pathStack.add(new ArrayList<>());
while(!nodeStack.isEmpty()){
TreeNode currNode = nodeStack.peek();
int currSum = sumStack.pop();
ArrayList<Integer> currPath = pathStack.pop();
if(currNode != null){
nodeStack.pop();
nodeStack.add(currNode);
nodeStack.add(null);
sumStack.add(currSum);
currPath.add(currNode.val);
pathStack.add(new ArrayList(currPath));
if(currNode.right != null){
nodeStack.add(currNode.right);
sumStack.add(currSum + currNode.right.val);
pathStack.add(new ArrayList(currPath));
}
if(currNode.left != null){
nodeStack.add(currNode.left);
sumStack.add(currSum + currNode.left.val);
pathStack.add(new ArrayList(currPath));
}
}else{
nodeStack.pop();
TreeNode temp = nodeStack.pop();
if(temp.left == null && temp.right == null && currSum == targetSum)
result.add(new ArrayList(currPath));
}
}
return result;
}
}
```
## python
### 0112.路径总和
**递归**
(版本一) 递归
```python
class solution:
def haspathsum(self, root: treenode, targetsum: int) -> bool:
def isornot(root, targetsum) -> bool:
if (not root.left) and (not root.right) and targetsum == 0:
return true # 遇到叶子节点并且计数为0
if (not root.left) and (not root.right):
return false # 遇到叶子节点计数不为0
if root.left:
targetsum -= root.left.val # 左节点
if isornot(root.left, targetsum): return true # 递归,处理左节点
targetsum += root.left.val # 回溯
if root.right:
targetsum -= root.right.val # 右节点
if isornot(root.right, targetsum): return true # 递归,处理右节点
targetsum += root.right.val # 回溯
return false
if root == none:
return false # 别忘记处理空treenode
else:
return isornot(root, targetsum - root.val)
# 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 traversal(self, cur: TreeNode, count: int) -> bool:
if not cur.left and not cur.right and count == 0: # 遇到叶子节点并且计数为0
return True
if not cur.left and not cur.right: # 遇到叶子节点直接返回
return False
if cur.left: # 左
count -= cur.left.val
if self.traversal(cur.left, count): # 递归,处理节点
return True
count += cur.left.val # 回溯,撤销处理结果
class Solution: # 简洁版
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root: return False
if root.left==root.right==None and root.val == targetSum: return True
return self.hasPathSum(root.left,targetSum-root.val) or self.hasPathSum(root.right,targetSum-root.val)
if cur.right: # 右
count -= cur.right.val
if self.traversal(cur.right, count): # 递归,处理节点
return True
count += cur.right.val # 回溯,撤销处理结果
return False
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
if root is None:
return False
return self.traversal(root, sum - root.val)
```
**迭代 - 层序遍历**
(版本二) 递归 + 精简
```python
class solution:
def haspathsum(self, root: treenode, targetsum: int) -> bool:
# 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 hasPathSum(self, root: TreeNode, sum: int) -> bool:
if not root:
return false
stack = [] # [(当前节点,路径数值), ...]
stack.append((root, root.val))
while stack:
cur_node, path_sum = stack.pop()
if not cur_node.left and not cur_node.right and path_sum == targetsum:
return true
if cur_node.right:
stack.append((cur_node.right, path_sum + cur_node.right.val))
if cur_node.left:
stack.append((cur_node.left, path_sum + cur_node.left.val))
return false
return False
if not root.left and not root.right and sum == root.val:
return True
return self.hasPathSum(root.left, sum - root.val) or self.hasPathSum(root.right, sum - root.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 hasPathSum(self, root: TreeNode, sum: int) -> bool:
if not root:
return False
# 此时栈里要放的是pair<节点指针,路径数值>
st = [(root, root.val)]
while st:
node, path_sum = st.pop()
# 如果该节点是叶子节点了同时该节点的路径数值等于sum那么就返回true
if not node.left and not node.right and path_sum == sum:
return True
# 右节点,压进去一个节点的时候,将该节点的路径数值也记录下来
if node.right:
st.append((node.right, path_sum + node.right.val))
# 左节点,压进去一个节点的时候,将该节点的路径数值也记录下来
if node.left:
st.append((node.left, path_sum + node.left.val))
return False
```
### 0113.路径总和-ii
**递归**
(版本一) 递归
```python
class solution:
def pathsum(self, root: treenode, targetsum: int) -> list[list[int]]:
# 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 __init__(self):
self.result = []
self.path = []
def traversal(cur_node, remain):
if not cur_node.left and not cur_node.right:
if remain == 0:
result.append(path[:])
return
def traversal(self, cur, count):
if not cur.left and not cur.right and count == 0: # 遇到了叶子节点且找到了和为sum的路径
self.result.append(self.path[:])
return
if cur_node.left:
path.append(cur_node.left.val)
traversal(cur_node.left, remain-cur_node.left.val)
path.pop()
if not cur.left and not cur.right: # 遇到叶子节点而没有找到合适的边,直接返回
return
if cur_node.right:
path.append(cur_node.right.val)
traversal(cur_node.right, remain-cur_node.right.val)
path.pop()
if cur.left: # 左 (空节点不遍历)
self.path.append(cur.left.val)
count -= cur.left.val
self.traversal(cur.left, count) # 递归
count += cur.left.val # 回溯
self.path.pop() # 回溯
result, path = [], []
if cur.right: # 右 (空节点不遍历)
self.path.append(cur.right.val)
count -= cur.right.val
self.traversal(cur.right, count) # 递归
count += cur.right.val # 回溯
self.path.pop() # 回溯
return
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
self.result.clear()
self.path.clear()
if not root:
return []
path.append(root.val)
traversal(root, targetsum - root.val)
return result
return self.result
self.path.append(root.val) # 把根节点放进路径
self.traversal(root, sum - root.val)
return self.result
```
**迭代法,用第二个队列保存目前的总和与路径**
(版本二) 递归 + 精简
```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 pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
if not root:
return []
que, temp = deque([root]), deque([(root.val, [root.val])])
def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
result = []
while que:
for _ in range(len(que)):
node = que.popleft()
value, path = temp.popleft()
if (not node.left) and (not node.right):
if value == targetSum:
result.append(path)
if node.left:
que.append(node.left)
temp.append((node.left.val+value, path+[node.left.val]))
if node.right:
que.append(node.right)
temp.append((node.right.val+value, path+[node.right.val]))
self.traversal(root, targetSum, [], result)
return result
def traversal(self,node, count, path, result):
if not node:
return
path.append(node.val)
count -= node.val
if not node.left and not node.right and count == 0:
result.append(list(path))
self.traversal(node.left, count, path, result)
self.traversal(node.right, count, path, result)
path.pop()
```
**迭代法,前序遍历**
(版本三) 迭代
```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 pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
if not root: return []
stack, path_stack,result = [[root,root.val]],[[root.val]],[]
def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
if not root:
return []
stack = [(root, [root.val])]
res = []
while stack:
cur,cursum = stack.pop()
path = path_stack.pop()
if cur.left==cur.right==None:
if cursum==targetSum: result.append(path)
if cur.right:
stack.append([cur.right,cursum+cur.right.val])
path_stack.append(path+[cur.right.val])
if cur.left:
stack.append([cur.left,cursum+cur.left.val])
path_stack.append(path+[cur.left.val])
return result
node, path = stack.pop()
if not node.left and not node.right and sum(path) == targetSum:
res.append(path)
if node.right:
stack.append((node.right, path + [node.right.val]))
if node.left:
stack.append((node.left, path + [node.left.val]))
return res
```
## go

View File

@ -14,16 +14,21 @@
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例 1
输入:[7,1,5,3,6,4]
输出5
* 示例 1
* 输入:[7,1,5,3,6,4]
* 输出5
解释:在第 2 天(股票价格 = 1的时候买入在第 5 天(股票价格 = 6的时候卖出最大利润 = 6-1 = 5 。注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2
输入prices = [7,6,4,3,1]
输出0
* 示例 2
* 输入prices = [7,6,4,3,1]
* 输出0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
# 算法公开课
**《代码随想录》算法视频公开课:[动态规划之 LeetCode121.买卖股票的最佳时机1](https://www.bilibili.com/video/BV1Xe4y1u77q),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -102,7 +102,7 @@ public:
### 动态规划
动态规划将在下一个系列详细讲解,本题解先给出我的 C++代码(带详细注释),感兴趣的同学可以自己先学习一下。
动态规划将在下一个系列详细讲解,本题解先给出我的 C++代码(带详细注释),想先学习的话,可以看本篇:[122.买卖股票的最佳时机II动态规划](https://programmercarl.com/0122.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BAII%EF%BC%88%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%EF%BC%89.html#%E6%80%9D%E8%B7%AF)
```CPP
class Solution {

View File

@ -15,25 +15,30 @@
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
* 示例 1:
* 输入: [7,1,5,3,6,4]
* 输出: 7
解释: 在第 2 天(股票价格 = 1的时候买入在第 3 天(股票价格 = 5的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。随后在第 4 天(股票价格 = 3的时候买入在第 5 天(股票价格 = 6的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
输入: [1,2,3,4,5]
输出: 4
* 示例 2:
* 输入: [1,2,3,4,5]
* 输出: 4
解释: 在第 1 天(股票价格 = 1的时候买入在第 5 天 (股票价格 = 5的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: [7,6,4,3,1]
输出: 0
* 示例 3:
* 输入: [7,6,4,3,1]
* 输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
提示:
* 1 <= prices.length <= 3 * 10 ^ 4
* 0 <= prices[i] <= 10 ^ 4
# 算法公开课
**《代码随想录》算法视频公开课:[动态规划,股票问题第二弹 | LeetCode122.买卖股票的最佳时机II](https://www.bilibili.com/video/BV1D24y1Q7Ls),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路
本题我们在讲解贪心专题的时候就已经讲解过了[贪心算法买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html),只不过没有深入讲解动态规划的解法,那么这次我们再好好分析一下动规的解法。

View File

@ -15,23 +15,23 @@
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入prices = [3,3,5,0,0,3,1,4]
输出6
* 示例 1:
* 输入prices = [3,3,5,0,0,3,1,4]
* 输出6
解释:在第 4 天(股票价格 = 0的时候买入在第 6 天(股票价格 = 3的时候卖出这笔交易所能获得利润 = 3-0 = 3 。随后,在第 7 天(股票价格 = 1的时候买入在第 8 天 (股票价格 = 4的时候卖出这笔交易所能获得利润 = 4-1 = 3。
示例 2
输入prices = [1,2,3,4,5]
输出4
* 示例 2
* 输入prices = [1,2,3,4,5]
* 输出4
解释:在第 1 天(股票价格 = 1的时候买入在第 5 天 (股票价格 = 5的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3
输入prices = [7,6,4,3,1]
输出0
* 示例 3
* 输入prices = [7,6,4,3,1]
* 输出0
解释:在这个情况下, 没有交易完成, 所以最大利润为0。
示例 4
输入prices = [1]
* 示例 4
* 输入prices = [1]
输出0
提示:
@ -39,6 +39,11 @@
* 1 <= prices.length <= 10^5
* 0 <= prices[i] <= 10^5
# 算法公开课
**《代码随想录》算法视频公开课:[动态规划,股票至多买卖两次,怎么求? | LeetCode123.买卖股票最佳时机III](https://www.bilibili.com/video/BV1WG411K7AR),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -209,6 +209,9 @@ public:
}
};
```
* 时间复杂度: O(n * 2^n)
* 空间复杂度: O(n^2)
# 优化
上面的代码还存在一定的优化空间, 在于如何更高效的计算一个子字符串是否是回文字串。上述代码```isPalindrome```函数运用双指针的方法来判定对于一个字符串```s```, 给定起始下标和终止下标, 截取出的子字符串是否是回文字串。但是其中有一定的重复计算存在:

View File

@ -221,25 +221,55 @@ public class Solution {
Python
```python
版本一快慢指针法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
slow, fast = head, head
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# 如果相遇
# If there is a cycle, the slow and fast pointers will eventually meet
if slow == fast:
p = head
q = slow
while p!=q:
p = p.next
q = q.next
#你也可以return q
return p
# Move one of the pointers back to the start of the list
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow
# If there is no cycle, return None
return None
```
```python
版本二集合法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
visited = set()
while head:
if head in visited:
return head
visited.add(head)
head = head.next
return None
```
Go
```go

View File

@ -434,134 +434,40 @@ class Solution {
```
python:
(版本一)先删除空白,然后整个反转,最后单词反转。
**因为字符串是不可变类型所以反转单词的时候需要将其转换成列表然后通过join函数再将其转换成列表所以空间复杂度不是O(1)**
```Python
class Solution:
#1.去除多余的空格
def trim_spaces(self, s):
n = len(s)
left = 0
right = n-1
while left <= right and s[left] == ' ': #去除开头的空格
left += 1
while left <= right and s[right] == ' ': #去除结尾的空格
right -= 1
tmp = []
while left <= right: #去除单词中间多余的空格
if s[left] != ' ':
tmp.append(s[left])
elif tmp[-1] != ' ': #当前位置是空格,但是相邻的上一个位置不是空格,则该空格是合理的
tmp.append(s[left])
left += 1
return tmp
#2.翻转字符数组
def reverse_string(self, nums, left, right):
while left < right:
nums[left], nums[right] = nums[right], nums[left]
left += 1
right -= 1
return None
#3.翻转每个单词
def reverse_each_word(self, nums):
start = 0
end = 0
n = len(nums)
while start < n:
while end < n and nums[end] != ' ':
end += 1
self.reverse_string(nums, start, end-1)
start = end + 1
end += 1
return None
#4.翻转字符串里的单词
def reverseWords(self, s): #测试用例:"the sky is blue"
l = self.trim_spaces(s) #输出:['t', 'h', 'e', ' ', 's', 'k', 'y', ' ', 'i', 's', ' ', 'b', 'l', 'u', 'e'
self.reverse_string(l, 0, len(l)-1) #输出:['e', 'u', 'l', 'b', ' ', 's', 'i', ' ', 'y', 'k', 's', ' ', 'e', 'h', 't']
self.reverse_each_word(l) #输出:['b', 'l', 'u', 'e', ' ', 'i', 's', ' ', 's', 'k', 'y', ' ', 't', 'h', 'e']
return ''.join(l) #输出blue is sky the
def reverseWords(self, s: str) -> str:
# 删除前后空白
s = s.strip()
# 反转整个字符串
s = s[::-1]
# 将字符串拆分为单词,并反转每个单词
s = ' '.join(word[::-1] for word in s.split())
return s
```
(版本二)使用双指针
```python
class Solution:
def reverseWords(self, s: str) -> str:
# method 1 - Rude but work & efficient method.
s_list = [i for i in s.split(" ") if len(i) > 0]
return " ".join(s_list[::-1])
# 将字符串拆分为单词,即转换成列表类型
words = s.split()
# method 2 - Carlo's idea
def trim_head_tail_space(ss: str):
p = 0
while p < len(ss) and ss[p] == " ":
p += 1
return ss[p:]
# 反转单词
left, right = 0, len(words) - 1
while left < right:
words[left], words[right] = words[right], words[left]
left += 1
right -= 1
# Trim the head and tail space
s = trim_head_tail_space(s)
s = trim_head_tail_space(s[::-1])[::-1]
pf, ps, s = 0, 0, s[::-1] # Reverse the string.
while pf < len(s):
if s[pf] == " ":
# Will not excede. Because we have clean the tail space.
if s[pf] == s[pf + 1]:
s = s[:pf] + s[pf + 1:]
continue
else:
s = s[:ps] + s[ps: pf][::-1] + s[pf:]
ps, pf = pf + 1, pf + 2
else:
pf += 1
return s[:ps] + s[ps:][::-1] # Must do the last step, because the last word is omit though the pointers are on the correct positions,
# 将列表转换成字符串
return " ".join(words)
```
```python
class Solution: # 使用双指针法移除空格
def reverseWords(self, s: str) -> str:
def removeextraspace(s):
start = 0; end = len(s)-1
while s[start]==' ':
start+=1
while s[end]==' ':
end-=1
news = list(s[start:end+1])
slow = fast = 0
while fast<len(news):
while fast>0 and news[fast]==news[fast-1]==' ':
fast+=1
news[slow]=news[fast]
slow+=1; fast+=1
#return "".join(news[:slow])
return news[:slow]
def reversestr(s):
left,right = 0,len(s)-1
news = list(s)
while left<right:
news[left],news[right] = news[right],news[left]
left+=1; right-=1
#return "".join(news)
return news
news = removeextraspace(s)
news.append(' ')
fast=slow=0
#print(news)
while fast<len(news):
while news[fast]!=' ':
fast+=1
news[slow:fast] = reversestr(news[slow:fast])
# print(news[slow:fast])
fast=slow=fast+1
news2 = reversestr(news[:-1])
return ''.join(news2)
```
Go
```go

View File

@ -14,14 +14,14 @@
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1
输入k = 2, prices = [2,4,1]
输出2
* 示例 1
* 输入k = 2, prices = [2,4,1]
* 输出2
解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2。
示例 2
输入k = 2, prices = [3,2,6,5,0,3]
输出7
* 示例 2
* 输入k = 2, prices = [3,2,6,5,0,3]
* 输出7
解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4。随后在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
@ -31,6 +31,11 @@
* 0 <= prices.length <= 1000
* 0 <= prices[i] <= 1000
# 算法公开课
**《代码随想录》算法视频公开课:[动态规划来决定最佳时机至多可以买卖K次| LeetCode188.买卖股票最佳时机4](https://www.bilibili.com/video/BV16M411U7XJ),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路
这道题目可以说是[动态规划123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)的进阶版这里要求至多有k次交易。

View File

@ -31,6 +31,10 @@
* 0 <= nums.length <= 100
* 0 <= nums[i] <= 400
# 算法公开课
**《代码随想录》算法视频公开课:[动态规划,偷不偷这个房间呢?| LeetCode198.打家劫舍](https://www.bilibili.com/video/BV1Te411N7SX),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路
@ -136,6 +140,29 @@ class Solution {
return dp[nums.length - 1];
}
}
// 空间优化 dp数组只存与计算相关的两次数据
class Solution {
public int rob(int[] nums) {
if (nums.length == 1) {
return nums[0];
}
// 初始化dp数组
// 优化空间 dp数组只用2格空间 只记录与当前计算相关的前两个结果
int[] dp = new int[2];
dp[0] = nums[0];
dp[1] = nums[0] > nums[1] ? 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];
dp[0] = dp[1];
dp[1] = res;
}
// 输出结果
return dp[1];
}
}
```
Python
@ -230,3 +257,4 @@ function rob(nums: number[]): number {
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>

View File

@ -108,23 +108,14 @@ class Solution {
```
Python
(版本一)使用集合
```python
class Solution:
def isHappy(self, n: int) -> bool:
def calculate_happy(num):
sum_ = 0
# 从个位开始依次取,平方求和
while num:
sum_ += (num % 10) ** 2
num = num // 10
return sum_
# 记录中间结果
def isHappy(self, n: int) -> bool:
record = set()
while True:
n = calculate_happy(n)
n = self.get_sum(n)
if n == 1:
return True
@ -134,21 +125,86 @@ class Solution:
else:
record.add(n)
# python的另一种写法 - 通过字符串来计算各位平方和
def get_sum(self,n: int) -> int:
new_num = 0
while n:
n, r = divmod(n, 10)
new_num += r ** 2
return new_num
```
(版本二)使用集合
```python
class Solution:
def isHappy(self, n: int) -> bool:
record = set()
while n not in record:
record.add(n)
new_num = 0
n_str = str(n)
for i in n_str:
new_num+=int(i)**2
if new_num==1: return True
else: n = new_num
return False
```
(版本三)使用数组
```python
class Solution:
def isHappy(self, n: int) -> bool:
record = []
while n not in record:
record.append(n)
newn = 0
nn = str(n)
for i in nn:
newn+=int(i)**2
if newn==1: return True
n = newn
new_num = 0
n_str = str(n)
for i in n_str:
new_num+=int(i)**2
if new_num==1: return True
else: n = new_num
return False
```
(版本四)使用快慢指针
```python
class Solution:
def isHappy(self, n: int) -> bool:
slow = n
fast = n
while self.get_sum(fast) != 1 and self.get_sum(self.get_sum(fast)):
slow = self.get_sum(slow)
fast = self.get_sum(self.get_sum(fast))
if slow == fast:
return False
return True
def get_sum(self,n: int) -> int:
new_num = 0
while n:
n, r = divmod(n, 10)
new_num += r ** 2
return new_num
```
(版本五)使用集合+精简
```python
class Solution:
def isHappy(self, n: int) -> bool:
seen = set()
while n != 1:
n = sum(int(i) ** 2 for i in str(n))
if n in seen:
return False
seen.add(n)
return True
```
(版本六)使用数组+精简
```python
class Solution:
def isHappy(self, n: int) -> bool:
seen = []
while n != 1:
n = sum(int(i) ** 2 for i in str(n))
if n in seen:
return False
seen.append(n)
return True
```
Go
```go
func isHappy(n int) bool {

View File

@ -307,21 +307,27 @@ public ListNode removeElements(ListNode head, int val) {
Python
```python
版本一虚拟头节点法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeElements(self, head: ListNode, val: int) -> ListNode:
dummy_head = ListNode(next=head) #添加一个虚拟节点
cur = dummy_head
while cur.next:
if cur.next.val == val:
cur.next = cur.next.next #删除cur.next节点
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
# 创建虚拟头部节点以简化删除过程
dummy_head = ListNode(next = head)
# 遍历列表并删除值为val的节点
current = dummy_head
while current.next:
if current.next.val == val:
current.next = current.next.next
else:
cur = cur.next
current = current.next
return dummy_head.next
```
Go

View File

@ -193,9 +193,9 @@ class Solution {
}
```
Python迭代法:
Python
```python
#双指针
版本一双指针
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
@ -205,7 +205,7 @@ class Solution:
def reverseList(self, head: ListNode) -> ListNode:
cur = head
pre = None
while(cur!=None):
while cur:
temp = cur.next # 保存一下 cur的下一个节点因为接下来要改变cur->next
cur.next = pre #反转
#更新pre、cur指针
@ -217,6 +217,7 @@ class Solution:
Python递归法
```python
版本二递归法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
@ -224,36 +225,17 @@ Python递归法
# self.next = next
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
def reverse(pre,cur):
if not cur:
return pre
tmp = cur.next
cur.next = pre
return reverse(cur,tmp)
return reverse(None,head)
return self.reverse(head, None)
def reverse(self, cur: ListNode, pre: ListNode) -> ListNode:
if cur == None:
return pre
temp = cur.next
cur.next = pre
return self.reverse(temp, cur)
```
Python递归法从后向前
```python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next: return head
p = self.reverseList(head.next)
head.next.next = head
head.next = None
return p
```
Go

View File

@ -173,18 +173,44 @@ class Solution {
Python
```python
版本一滑动窗口法
class Solution:
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
res = float("inf") # 定义一个无限大的数
Sum = 0 # 滑动窗口数值之和
i = 0 # 滑动窗口起始位置
for j in range(len(nums)):
Sum += nums[j]
while Sum >= s:
res = min(res, j-i+1)
Sum -= nums[i]
i += 1
return 0 if res == float("inf") else res
l = len(nums)
left = 0
right = 0
min_len = float('inf')
cur_sum = 0 #当前的累加值
while right < l:
cur_sum += nums[right]
while cur_sum >= s: # 当前累加值大于目标值
min_len = min(min_len, right - left + 1)
cur_sum -= nums[left]
left += 1
right += 1
return min_len if min_len != float('inf') else 0
```
```python
版本二暴力法
class Solution:
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
l = len(nums)
min_len = float('inf')
for i in range(l):
cur_sum = 0
for j in range(i, l):
cur_sum += nums[j]
if cur_sum >= s:
min_len = min(min_len, j - i + 1)
break
return min_len if min_len != float('inf') else 0
```
Go

View File

@ -14,23 +14,28 @@
示例 1
输入nums = [2,3,2]
输出3
解释:你不能先偷窃 1 号房屋(金额 = 2然后偷窃 3 号房屋(金额 = 2, 因为他们是相邻的。
* 输入nums = [2,3,2]
* 输出3
* 解释:你不能先偷窃 1 号房屋(金额 = 2然后偷窃 3 号房屋(金额 = 2, 因为他们是相邻的。
示例 2
输入nums = [1,2,3,1]
输出4
解释:你可以先偷窃 1 号房屋(金额 = 1然后偷窃 3 号房屋(金额 = 3。偷窃到的最高金额 = 1 + 3 = 4 。
* 示例 2
* 输入nums = [1,2,3,1]
* 输出4
* 解释:你可以先偷窃 1 号房屋(金额 = 1然后偷窃 3 号房屋(金额 = 3。偷窃到的最高金额 = 1 + 3 = 4 。
示例 3
输入nums = [0]
输出0
* 示例 3
* 输入nums = [0]
* 输出0
提示:
* 1 <= nums.length <= 100
* 0 <= nums[i] <= 1000
# 算法公开课
**《代码随想录》算法视频公开课:[动态规划,房间连成环了那还偷不偷呢?| LeetCode213.打家劫舍II](https://www.bilibili.com/video/BV1oM411B7xq),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路
这道题目和[198.打家劫舍](https://programmercarl.com/0198.打家劫舍.html)是差不多的,唯一区别就是成环了。

View File

@ -235,6 +235,8 @@ public:
}
};
```
* 时间复杂度: O(n * 2^n)
* 空间复杂度: O(n)
# 总结

View File

@ -393,6 +393,20 @@ class Solution: # 利用完全二叉树特性
return 2**count-1
return 1+self.countNodes(root.left)+self.countNodes(root.right)
```
完全二叉树写法3
```python
class Solution: # 利用完全二叉树特性
def countNodes(self, root: TreeNode) -> int:
if not root: return 0
count = 0
left = root.left; right = root.right
while left and right:
count+=1
left = left.left; right = right.right
if not left and not right: # 如果同时到底说明是满二叉树,反之则不是
return (2<<count)-1
return 1+self.countNodes(root.left)+self.countNodes(root.right)
```
## Go

View File

@ -166,7 +166,7 @@ public:
Java
使用两个 Queue 实现
使用两个 Queue 实现方法1
```java
class MyStack {
@ -208,6 +208,42 @@ class MyStack {
}
```
使用两个 Queue 实现方法2
```java
class MyStack {
//q1作为主要的队列其元素排列顺序和出栈顺序相同
Queue<Integer> q1 = new ArrayDeque<>();
//q2仅作为临时放置
Queue<Integer> q2 = new ArrayDeque<>();
public MyStack() {
}
//在加入元素时先将q1中的元素依次出栈压入q2然后将新加入的元素压入q1再将q2中的元素依次出栈压入q1
public void push(int x) {
while (q1.size() > 0) {
q2.add(q1.poll());
}
q1.add(x);
while (q2.size() > 0) {
q1.add(q2.poll());
}
}
public int pop() {
return q1.poll();
}
public int top() {
return q1.peek();
}
public boolean empty() {
return q1.isEmpty();
}
}
```
使用两个 Deque 实现
```java
class MyStack {
@ -329,6 +365,43 @@ class MyStack {
}
}
```
优化,使用一个 Queue 实现,但用卡哥的逻辑实现
```
class MyStack {
Queue<Integer> queue;
public MyStack() {
queue = new LinkedList<>();
}
public void push(int x) {
queue.add(x);
}
public int pop() {
rePosition();
return queue.poll();
}
public int top() {
rePosition();
int result = queue.poll();
queue.add(result);
return result;
}
public boolean empty() {
return queue.isEmpty();
}
public void rePosition(){
int size = queue.size();
size--;
while(size-->0)
queue.add(queue.poll());
}
}
```
Python

View File

@ -314,81 +314,158 @@ class Solution {
递归法:前序遍历:
```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 invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
root.left, root.right = root.right, root.left #中
self.invertTree(root.left) #左
self.invertTree(root.right) #右
root.left, root.right = root.right, root.left
self.invertTree(root.left)
self.invertTree(root.right)
return 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 invertTree(self, root: TreeNode) -> TreeNode:
if root is None:
if not root:
return None
stack = [root]
while stack:
node = stack.pop()
node.left, node.right = node.right, node.left
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
return 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 invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
self.invertTree(root.left)
root.left, root.right = root.right, root.left
self.invertTree(root.left)
return 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 invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
stack = [root]
while stack:
node = stack.pop()
if node.left:
stack.append(node.left)
node.left, node.right = node.right, node.left
if node.left:
stack.append(node.left)
return 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 invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
self.invertTree(root.left)
self.invertTree(root.right)
root.left, root.right = root.right, root.left
return root
return 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 invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return root
st = []
st.append(root)
while st:
node = st.pop()
node.left, node.right = node.right, node.left #中
if node.right:
st.append(node.right) #右
return None
stack = [root]
while stack:
node = stack.pop()
if node.left:
st.append(node.left) #左
stack.append(node.left)
if node.right:
stack.append(node.right)
node.left, node.right = node.right, node.left
return root
```
迭代法:广度优先遍历(层序遍历):
```python
import collections
# 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 invertTree(self, root: TreeNode) -> TreeNode:
queue = collections.deque() #使用deque()
if root:
queue.append(root)
if not root:
return None
queue = collections.deque([root])
while queue:
size = len(queue)
for i in range(size):
for i in range(len(queue)):
node = queue.popleft()
node.left, node.right = node.right, node.left #节点处理
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return root
```
迭代法:广度优先遍历(层序遍历),和之前的层序遍历写法一致:
```python
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root: return root
from collections import deque
que=deque([root])
while que:
size=len(que)
for i in range(size):
cur=que.popleft()
cur.left, cur.right = cur.right, cur.left
if cur.left: que.append(cur.left)
if cur.right: que.append(cur.right)
node.left, node.right = node.right, node.left
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
return root
```
### Go
递归版本的前序遍历
@ -914,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"/>

View File

@ -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
递归法:

View File

@ -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

View File

@ -122,6 +122,7 @@ class Solution {
```
Python
```python
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
@ -137,7 +138,6 @@ class Solution:
return False
return True
```
Python写法二没有使用数组作为哈希表只是介绍defaultdict这样一种解题思路
```python
@ -147,13 +147,11 @@ class Solution:
s_dict = defaultdict(int)
t_dict = defaultdict(int)
for x in s:
s_dict[x] += 1
for x in t:
t_dict[x] += 1
return s_dict == t_dict
```
Python写法三(没有使用数组作为哈希表只是介绍Counter这种更方便的解题思路)
@ -165,7 +163,6 @@ class Solution(object):
a_count = Counter(s)
b_count = Counter(t)
return a_count == b_count
```
Go

View File

@ -468,7 +468,67 @@ class Solution {
```
---
## Python:
递归法+隐形回溯
递归法+回溯
```Python
# Definition for a binary tree node.
class Solution:
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 = []
path = []
if not root:
return result
self.traversal(root, path, result)
return result
```
递归法+隐形回溯(版本一)
```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 typing import List, Optional
class Solution:
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
if not root:
return []
result = []
self.traversal(root, [], result)
return result
def traversal(self, cur: TreeNode, path: List[int], result: List[str]) -> None:
if not cur:
return
path.append(cur.val)
if not cur.left and not cur.right:
result.append('->'.join(map(str, path)))
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:
@ -501,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()

View File

@ -149,7 +149,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]:

View File

@ -20,6 +20,10 @@
* 输出: 3
* 解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
# 算法公开课
**《代码随想录》算法视频公开课:[动态规划来决定最佳时机,这次有冷冻期!| LeetCode309.买卖股票的最佳时机含冷冻期](https://www.bilibili.com/video/BV1rP4y1D7ku),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -16,6 +16,11 @@
![337.打家劫舍III](https://code-thinking-1253855093.file.myqcloud.com/pics/20210223173849619.png)
# 算法公开课
**《代码随想录》算法视频公开课:[动态规划,房间连成树了,偷不偷呢?| LeetCode337.打家劫舍3](https://www.bilibili.com/video/BV1H24y1Q7sY),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路
这道题目和 [198.打家劫舍](https://programmercarl.com/0198.打家劫舍.html)[213.打家劫舍II](https://programmercarl.com/0213.打家劫舍II.html)也是如出一辙,只不过这个换成了树。

View File

@ -254,7 +254,7 @@ class Solution:
# 假设对正整数 i 拆分出的第一个正整数是 j1 <= j < i则有以下两种方案
# 1) 将 i 拆分成 j 和 ij 的和,且 ij 不再拆分成多个正整数,此时的乘积是 j * (i-j)
# 2) 将 i 拆分成 j 和 ij 的和,且 ij 继续拆分成多个正整数,此时的乘积是 j * dp[i-j]
for j in range(1, i / 2 + 1):
for j in range(1, i // 2 + 1):
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
return dp[n]
```
@ -319,6 +319,29 @@ pub fn integer_break(n: i32) -> i32 {
}
```
贪心
```rust
impl Solution {
pub fn integer_break(mut n: i32) -> i32 {
match n {
2 => 1,
3 => 2,
4 => 4,
5.. => {
let mut res = 1;
while n > 4 {
res *= 3;
n -= 3;
}
res * n
}
_ => panic!("Error"),
}
}
}
```
### TypeScript
```typescript
@ -344,27 +367,6 @@ function integerBreak(n: number): number {
};
```
### Rust
```Rust
impl Solution {
fn max(a: i32, b: i32) -> i32{
if a > b { a } else { b }
}
pub fn integer_break(n: i32) -> i32 {
let n = n as usize;
let mut dp = vec![0; n + 1];
dp[2] = 1;
for i in 3..=n {
for j in 1..i - 1 {
dp[i] = Self::max(dp[i], Self::max(((i - j) * j) as i32, dp[i - j] * j as i32));
}
}
dp[n]
}
}
```
### C
```c

View File

@ -174,6 +174,7 @@ class Solution {
```
Python
(版本一) 双指针
```python
class Solution:
def reverseString(self, s: List[str]) -> None:
@ -182,15 +183,70 @@ class Solution:
"""
left, right = 0, len(s) - 1
# 该方法已经不需要判断奇偶数,经测试后时间空间复杂度比用 for i in range(right//2)更低
# 推荐该写法,更加通俗易懂
# 该方法已经不需要判断奇偶数,经测试后时间空间复杂度比用 for i in range(len(s)//2)更低
# 因为while每次循环需要进行条件判断而range函数不需要直接生成数字因此时间复杂度更低。推荐使用range
while left < right:
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
```
(版本二) 使用栈
```python
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
stack = []
for char in s:
stack.append(char)
for i in range(len(s)):
s[i] = stack.pop()
```
(版本三) 使用range
```python
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
n = len(s)
for i in range(n // 2):
s[i], s[n - i - 1] = s[n - i - 1], s[i]
```
(版本四) 使用reversed
```python
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
s[:] = reversed(s)
```
(版本五) 使用切片
```python
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
s[:] = s[::-1]
```
(版本六) 使用列表推导
```python
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
s[:] = [s[i] for i in range(len(s) - 1, -1, -1)]
```
Go
```Go
func reverseString(s []byte) {

View File

@ -188,7 +188,33 @@ class Solution {
}
}
```
简化版代码:
```java
class Solution {
public int[] topKFrequent(int[] nums, int k) {
// 优先级队列,为了避免复杂 api 操作pq 存储数组
// lambda 表达式设置优先级队列从大到小存储 o1 - o2 为从大到小o2 - o1 反之
PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);
int[] res = new int[k]; // 答案数组为 k 个元素
Map<Integer, Integer> map = new HashMap<>(); // 记录元素出现次数
for(int num : nums) map.put(num, map.getOrDefault(num, 0) + 1);
for(var x : map.entrySet()) { // entrySet 获取 k-v Set 集合
// 将 kv 转化成数组
int[] tmp = new int[2];
tmp[0] = x.getKey();
tmp[1] = x.getValue();
pq.offer(tmp);
if(pq.size() > k) {
pq.poll();
}
}
for(int i = 0; i < k; i ++) {
res[i] = pq.poll()[0]; // 获取优先队列里的元素
}
return res;
}
}
```
Python
```python

View File

@ -160,22 +160,29 @@ class Solution {
```
Python3
(版本一) 使用字典和集合
```python
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
val_dict = {}
ans = []
# 使用哈希表存储一个数组中的所有元素
table = {}
for num in nums1:
val_dict[num] = 1
for num in nums2:
if num in val_dict.keys() and val_dict[num] == 1:
ans.append(num)
val_dict[num] = 0
table[num] = table.get(num, 0) + 1
return ans
# 使用集合存储结果
res = set()
for num in nums2:
if num in table:
res.add(num)
del table[num]
return list(res)
```
(版本二) 使用数组
```python
class Solution: # 使用数组方法
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
count1 = [0]*1001
count2 = [0]*1001
@ -190,7 +197,14 @@ class Solution: # 使用数组方法
return result
```
(版本三) 使用集合
```python
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
return list(set(nums1) & set(nums2))
```
Go
```go

View File

@ -117,6 +117,10 @@ Java
```Java
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
// shortcut
if (ransomNote.length() > magazine.length()) {
return false;
}
// 定义一个哈希映射数组
int[] record = new int[26];
@ -142,34 +146,27 @@ class Solution {
```
Python写法一使用数组作为哈希表
(版本一)使用数组
```python
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
arr = [0] * 26
for x in magazine: # 记录 magazine里各个字符出现次数
arr[ord(x) - ord('a')] += 1
for x in ransomNote: # 在arr里对应的字符个数做--操作
if arr[ord(x) - ord('a')] == 0: # 如果没有出现过直接返回
return False
else:
arr[ord(x) - ord('a')] -= 1
return True
ransom_count = [0] * 26
magazine_count = [0] * 26
for c in ransomNote:
ransom_count[ord(c) - ord('a')] += 1
for c in magazine:
magazine_count[ord(c) - ord('a')] += 1
return all(ransom_count[i] <= magazine_count[i] for i in range(26))
```
Python写法二使用defaultdict
版本二)使用defaultdict
```python
from collections import defaultdict
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
from collections import defaultdict
hashmap = defaultdict(int)
for x in magazine:
@ -177,59 +174,43 @@ class Solution:
for x in ransomNote:
value = hashmap.get(x)
if value is None or value == 0:
if not value or not value:
return False
else:
hashmap[x] -= 1
return True
```
Python写法三
```python
class Solution(object):
def canConstruct(self, ransomNote, magazine):
"""
:type ransomNote: str
:type magazine: str
:rtype: bool
"""
# use a dict to store the number of letter occurance in ransomNote
hashmap = dict()
for s in ransomNote:
if s in hashmap:
hashmap[s] += 1
else:
hashmap[s] = 1
# check if the letter we need can be found in magazine
for l in magazine:
if l in hashmap:
hashmap[l] -= 1
for key in hashmap:
if hashmap[key] > 0:
return False
return True
```
Python写法四
(版本三)使用字典
```python
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
c1 = collections.Counter(ransomNote)
c2 = collections.Counter(magazine)
x = c1 - c2
#x只保留值大于0的符号当c1里面的符号个数小于c2时不会被保留
#所以x只保留下了magazine不能表达的
if(len(x)==0):
return True
else:
return False
counts = {}
for c in magazine:
counts[c] = counts.get(c, 0) + 1
for c in ransomNote:
if c not in counts or counts[c] == 0:
return False
counts[c] -= 1
return True
```
版本四使用Counter
```python
from collections import Counter
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
return not Counter(ransomNote) - Counter(magazine)
```
版本五使用count
```python
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
return all(ransomNote.count(c) <= magazine.count(c) for c in set(ransomNote))
```
Go

View File

@ -247,49 +247,73 @@ 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 sumOfLeftLeaves(self, root: 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
left_left_leaves_sum = self.sumOfLeftLeaves(root.left) # 左
right_left_leaves_sum = self.sumOfLeftLeaves(root.right) #
cur_left_leaf_val = 0
if root.left and not root.left.left and not root.left.right:
cur_left_leaf_val = root.left.val
leftValue = self.sumOfLeftLeaves(root.left) # 左
if root.left and not root.left.left and not root.left.right: # 左子树是左叶子的情况
leftValue = root.left.val
return cur_left_leaf_val + left_left_leaves_sum + right_left_leaves_sum #
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

View File

@ -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
}
}
```

View File

@ -406,24 +406,21 @@ var canPartition = function(nums) {
```Rust
impl Solution {
fn max(a: usize, b: usize) -> usize {
if a > b { a } else { b }
}
pub fn can_partition(nums: Vec<i32>) -> bool {
let nums = nums.iter().map(|x| *x as usize).collect::<Vec<usize>>();
let mut sum = 0;
let mut dp: Vec<usize> = vec![0; 10001];
for i in 0..nums.len() {
sum += nums[i];
let sum = nums.iter().sum::<i32>() as usize;
if sum % 2 == 1 {
return false;
}
if sum % 2 == 1 { return false; }
let target = sum / 2;
for i in 0..nums.len() {
for j in (nums[i]..=target).rev() {
dp[j] = Self::max(dp[j], dp[j - nums[i]] + nums[i]);
let mut dp = vec![0; target + 1];
for n in nums {
for j in (n as usize..=target).rev() {
dp[j] = dp[j].max(dp[j - n as usize] + n)
}
}
if dp[target] == target { return true; }
if dp[target] == target as i32 {
return true;
}
false
}
}

View File

@ -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"/>

View File

@ -102,21 +102,14 @@ class Solution {
//统计两个数组中的元素之和同时统计出现的次数放入map
for (int i : nums1) {
for (int j : nums2) {
int tmp = map.getOrDefault(i + j, 0);
if (tmp == 0) {
map.put(i + j, 1);
} else {
map.replace(i + j, tmp + 1);
}
int sum = i + j;
map.put(sum, map.getOrDefault(sum, 0) + 1);
}
}
//统计剩余的两个元素的和在map中找是否存在相加为0的情况同时记录次数
for (int i : nums3) {
for (int j : nums4) {
int tmp = map.getOrDefault(0 - i - j, 0);
if (tmp != 0) {
res += tmp;
}
res += map.getOrDefault(0 - i - j, 0);
}
}
return res;
@ -125,11 +118,11 @@ class Solution {
```
Python
(版本一) 使用字典
```python
class Solution(object):
def fourSumCount(self, nums1, nums2, nums3, nums4):
# use a dict to store the elements in nums1 and nums2 and their sum
# 使用字典存储nums1和nums2中的元素及其和
hashmap = dict()
for n1 in nums1:
for n2 in nums2:
@ -138,7 +131,7 @@ class Solution(object):
else:
hashmap[n1+n2] = 1
# if the -(a+b) exists in nums3 and nums4, we shall add the count
# 如果 -(n1+n2) 存在于nums3和nums4, 存入结果
count = 0
for n3 in nums3:
for n4 in nums4:
@ -149,20 +142,40 @@ class Solution(object):
```
(版本二) 使用字典
```python
class Solution(object):
def fourSumCount(self, nums1, nums2, nums3, nums4):
# 使用字典存储nums1和nums2中的元素及其和
hashmap = dict()
for n1 in nums1:
for n2 in nums2:
hashmap[n1+n2] = hashmap.get(n1+n2, 0) + 1
# 如果 -(n1+n2) 存在于nums3和nums4, 存入结果
count = 0
for n3 in nums3:
for n4 in nums4:
key = - n3 - n4
if key in hashmap:
count += hashmap[key]
return count
```
(版本三)使用 defaultdict
```python
from collections import defaultdict
class Solution:
def fourSumCount(self, nums1: list, nums2: list, nums3: list, nums4: list) -> int:
from collections import defaultdict # You may use normal dict instead.
rec, cnt = defaultdict(lambda : 0), 0
# To store the summary of all the possible combinations of nums1 & nums2, together with their frequencies.
for i in nums1:
for j in nums2:
rec[i+j] += 1
# To add up the frequencies if the corresponding value occurs in the dictionary
for i in nums3:
for j in nums4:
cnt += rec.get(-(i+j), 0) # No matched key, return 0.
cnt += rec.get(-(i+j), 0)
return cnt
```

View File

@ -264,8 +264,7 @@ class Solution {
Python
这里使用了前缀表统一减一的实现方式
(版本一) 前缀表 减一
```python
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
@ -289,7 +288,7 @@ class Solution:
return nxt
```
前缀表不减一)的代码实现
(版本二) 前缀表 不减一
```python
class Solution:
@ -314,6 +313,40 @@ class Solution:
return nxt
```
(版本三) 使用 find
```python
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
n = len(s)
if n <= 1:
return False
ss = s[1:] + s[:-1]
print(ss.find(s))
return ss.find(s) != -1
```
(版本四) 暴力法
```python
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
n = len(s)
if n <= 1:
return False
substr = ""
for i in range(1, n//2 + 1):
if n % i == 0:
substr = s[:i]
if substr * (n//i) == s:
return True
return False
```
Go
这里使用了前缀表统一减一的实现方式

View File

@ -139,6 +139,8 @@ public:
}
};
```
* 时间复杂度: O(n * 2^n)
* 空间复杂度: O(n)
## 优化

View File

@ -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

View File

@ -271,52 +271,85 @@ class Solution {
### Python
递归:
(版本一)递归法 + 回溯
```python
class Solution:
def findBottomLeftValue(self, root: TreeNode) -> int:
max_depth = -float("INF")
leftmost_val = 0
self.max_depth = float('-inf')
self.result = None
self.traversal(root, 0)
return self.result
def traversal(self, node, depth):
if not node.left and not node.right:
if depth > self.max_depth:
self.max_depth = depth
self.result = node.val
return
if node.left:
depth += 1
self.traversal(node.left, depth)
depth -= 1
if node.right:
depth += 1
self.traversal(node.right, depth)
depth -= 1
def __traverse(root, cur_depth):
nonlocal max_depth, leftmost_val
if not root.left and not root.right:
if cur_depth > max_depth:
max_depth = cur_depth
leftmost_val = root.val
if root.left:
cur_depth += 1
__traverse(root.left, cur_depth)
cur_depth -= 1
if root.right:
cur_depth += 1
__traverse(root.right, cur_depth)
cur_depth -= 1
__traverse(root, 0)
return leftmost_val
```
迭代 - 层序遍历:
(版本二)递归法+精简
```python
class Solution:
def findBottomLeftValue(self, root: TreeNode) -> int:
self.max_depth = float('-inf')
self.result = None
self.traversal(root, 0)
return self.result
def traversal(self, node, depth):
if not node.left and not node.right:
if depth > self.max_depth:
self.max_depth = depth
self.result = node.val
return
if node.left:
self.traversal(node.left, depth+1)
if node.right:
self.traversal(node.right, depth+1)
```
(版本三) 迭代法
```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 findBottomLeftValue(self, root):
if root is None:
return 0
queue = deque()
if root:
queue.append(root)
queue.append(root)
result = 0
while queue:
q_len = len(queue)
for i in range(q_len):
if i == 0:
result = queue[i].val
cur = queue.popleft()
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
while queue:
size = len(queue)
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)
return result
```
### Go

View File

@ -174,6 +174,39 @@ class Solution {
}
}
```
統一迭代法-中序遍历
```Java
class Solution {
public int getMinimumDifference(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode pre = null;
int result = Integer.MAX_VALUE;
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)
result = Math.min(result, temp.val - pre.val);
pre = temp;
}
}
return result;
}
}
```
迭代法-中序遍历
```java
@ -204,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
中序遍历,然后计算最小差值

View File

@ -200,8 +200,30 @@ 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 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 +256,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]:

View File

@ -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

View File

@ -238,33 +238,45 @@ 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 result;
}
}
```
动态规划:简洁版
```java
class Solution {
public int countSubstrings(String s) {
boolean[][] dp = new boolean[s.length()][s.length()];
int res = 0;
for (int i = s.length() - 1; i >= 0; i--) {
for (int j = i; j < s.length(); j++) {
if (s.charAt(i) == s.charAt(j) && (j - i <= 1 || dp[i + 1][j - 1])) {
res++;
dp[i][j] = true;
}
}
}
return ans;
return res;
}
}
```

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -256,132 +256,103 @@ 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
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
```
-----

View File

@ -485,177 +485,176 @@ class MyLinkedList {
Python
```python
# 单链表
class Node(object):
def __init__(self, x=0):
self.val = x
self.next = None
class MyLinkedList(object):
def __init__(self):
self.head = Node()
self.size = 0 # 设置一个链表长度的属性,便于后续操作,注意每次增和删的时候都要更新
def get(self, index):
"""
:type index: int
:rtype: int
"""
if index < 0 or index >= self.size:
return -1
cur = self.head.next
while(index):
cur = cur.next
index -= 1
return cur.val
def addAtHead(self, val):
"""
:type val: int
:rtype: None
"""
new_node = Node(val)
new_node.next = self.head.next
self.head.next = new_node
self.size += 1
def addAtTail(self, val):
"""
:type val: int
:rtype: None
"""
new_node = Node(val)
cur = self.head
while(cur.next):
cur = cur.next
cur.next = new_node
self.size += 1
def addAtIndex(self, index, val):
"""
:type index: int
:type val: int
:rtype: None
"""
if index < 0:
self.addAtHead(val)
return
elif index == self.size:
self.addAtTail(val)
return
elif index > self.size:
return
node = Node(val)
pre = self.head
while(index):
pre = pre.next
index -= 1
node.next = pre.next
pre.next = node
self.size += 1
def deleteAtIndex(self, index):
"""
:type index: int
:rtype: None
"""
if index < 0 or index >= self.size:
return
pre = self.head
while(index):
pre = pre.next
index -= 1
pre.next = pre.next.next
self.size -= 1
# 双链表
# 相对于单链表, Node新增了prev属性
class Node:
def __init__(self, val):
版本一单链表
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.prev = None
self.next = None
self.next = next
class MyLinkedList:
def __init__(self):
self._head, self._tail = Node(0), Node(0) # 虚拟节点
self._head.next, self._tail.prev = self._tail, self._head
self._count = 0 # 添加的节点数
def _get_node(self, index: int) -> Node:
# 当index小于_count//2时, 使用_head查找更快, 反之_tail更快
if index >= self._count // 2:
# 使用prev往前找
node = self._tail
for _ in range(self._count - index):
node = node.prev
else:
# 使用next往后找
node = self._head
for _ in range(index + 1):
node = node.next
return node
self.dummy_head = ListNode()
self.size = 0
def get(self, index: int) -> int:
"""
Get the value of the index-th node in the linked list. If the index is invalid, return -1.
"""
if 0 <= index < self._count:
node = self._get_node(index)
return node.val
else:
if index < 0 or index >= self.size:
return -1
current = self.dummy_head.next
for i in range(index):
current = current.next
return current.val
def addAtHead(self, val: int) -> None:
"""
Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
"""
self._update(self._head, self._head.next, val)
self.dummy_head.next = ListNode(val, self.dummy_head.next)
self.size += 1
def addAtTail(self, val: int) -> None:
"""
Append a node of value val to the last element of the linked list.
"""
self._update(self._tail.prev, self._tail, val)
current = self.dummy_head
while current.next:
current = current.next
current.next = ListNode(val)
self.size += 1
def addAtIndex(self, index: int, val: int) -> None:
"""
Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
"""
if index < 0:
index = 0
elif index > self._count:
if index < 0 or index > self.size:
return
node = self._get_node(index)
self._update(node.prev, node, val)
def _update(self, prev: Node, next: Node, val: int) -> None:
"""
更新节点
:param prev: 相对于更新的前一个节点
:param next: 相对于更新的后一个节点
:param val: 要添加的节点值
"""
# 计数累加
self._count += 1
node = Node(val)
prev.next, next.prev = node, node
node.prev, node.next = prev, next
current = self.dummy_head
for i in range(index):
current = current.next
current.next = ListNode(val, current.next)
self.size += 1
def deleteAtIndex(self, index: int) -> None:
"""
Delete the index-th node in the linked list, if the index is valid.
"""
if 0 <= index < self._count:
node = self._get_node(index)
# 计数-1
self._count -= 1
node.prev.next, node.next.prev = node.next, node.prev
if index < 0 or index >= self.size:
return
current = self.dummy_head
for i in range(index):
current = current.next
current.next = current.next.next
self.size -= 1
# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)
```
```python
版本二双链表法
class ListNode:
def __init__(self, val=0, prev=None, next=None):
self.val = val
self.prev = prev
self.next = next
class MyLinkedList:
def __init__(self):
self.head = None
self.tail = None
self.size = 0
def get(self, index: int) -> int:
if index < 0 or index >= self.size:
return -1
if index < self.size // 2:
current = self.head
for i in range(index):
current = current.next
else:
current = self.tail
for i in range(self.size - index - 1):
current = current.prev
return current.val
def addAtHead(self, val: int) -> None:
new_node = ListNode(val, None, self.head)
if self.head:
self.head.prev = new_node
else:
self.tail = new_node
self.head = new_node
self.size += 1
def addAtTail(self, val: int) -> None:
new_node = ListNode(val, self.tail, None)
if self.tail:
self.tail.next = new_node
else:
self.head = new_node
self.tail = new_node
self.size += 1
def addAtIndex(self, index: int, val: int) -> None:
if index < 0 or index > self.size:
return
if index == 0:
self.addAtHead(val)
elif index == self.size:
self.addAtTail(val)
else:
if index < self.size // 2:
current = self.head
for i in range(index - 1):
current = current.next
else:
current = self.tail
for i in range(self.size - index):
current = current.prev
new_node = ListNode(val, current, current.next)
current.next.prev = new_node
current.next = new_node
self.size += 1
def deleteAtIndex(self, index: int) -> None:
if index < 0 or index >= self.size:
return
if index == 0:
self.head = self.head.next
if self.head:
self.head.prev = None
else:
self.tail = None
elif index == self.size - 1:
self.tail = self.tail.prev
if self.tail:
self.tail.next = None
else:
self.head = None
else:
if index < self.size // 2:
current = self.head
for i in range(index):
current = current.next
else:
current = self.tail
for i in range(self.size - index - 1):
current = current.prev
current.prev.next = current.next
current.next.prev = current.prev
self.size -= 1
# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)
```
Go

View File

@ -32,6 +32,11 @@
* 0 < prices[i] < 50000.
* 0 <= fee < 50000.
# 算法公开课
**代码随想录算法视频公开课[动态规划来决定最佳时机,这次含手续费!| LeetCode714.买卖股票的最佳时机含手续费](https://www.bilibili.com/video/BV1z44y1Z7UR)相信结合视频再看本篇题解更有助于大家对本题的理解**。
## 思路
本题贪心解法[贪心算法:买卖股票的最佳时机含手续费](https://programmercarl.com/0714.买卖股票的最佳时机含手续费.html)

View File

@ -140,22 +140,37 @@ class Solution {
Python
```Python
版本一双指针法
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
n = len(nums)
i,j,k = 0,n - 1,n - 1
ans = [-1] * n
while i <= j:
lm = nums[i] ** 2
rm = nums[j] ** 2
if lm > rm:
ans[k] = lm
i += 1
l, r, i = 0, len(nums)-1, len(nums)-1
res = [float('inf')] * len(nums) # 需要提前定义列表,存放结果
while l <= r:
if nums[l] ** 2 < nums[r] ** 2: # 左右边界进行对比,找出最大值
res[i] = nums[r] ** 2
r -= 1 # 右指针往左移动
else:
ans[k] = rm
j -= 1
k -= 1
return ans
res[i] = nums[l] ** 2
l += 1 # 左指针往右移动
i -= 1 # 存放结果的指针需要往前平移一位
return res
```
```Python
版本二暴力排序法
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
for i in range(len(nums)):
nums[i] *= nums[i]
nums.sort()
return nums
```
```Python
版本三暴力排序法+列表推导法
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
return sorted(x*x for x in nums)
```
Go

View File

@ -130,30 +130,6 @@ class Solution {
}
```
```java
class Solution {
public int largestSumAfterKNegations(int[] A, int K) {
if (A.length == 1) return k % 2 == 0 ? A[0] : -A[0];
Arrays.sort(A);
int sum = 0;
int idx = 0;
for (int i = 0; i < K; i++) {
if (i < A.length - 1 && A[idx] < 0) {
A[idx] = -A[idx];
if (A[idx] >= Math.abs(A[idx + 1])) idx++;
continue;
}
A[idx] = -A[idx];
}
for (int i = 0; i < A.length; i++) {
sum += A[i];
}
return sum;
}
}
```
### Python
```python
class Solution:

View File

@ -264,14 +264,15 @@ javaScript:
```js
var removeDuplicates = function(s) {
const stack = [];
for(const x of s) {
let c = null;
if(stack.length && x === (c = stack.pop())) continue;
c && stack.push(c);
stack.push(x);
const result = []
for(const i of s){
if(i === result[result.length-1]){
result.pop()
}else{
result.push(i)
}
}
return stack.join("");
return result.join('')
};
```

View File

@ -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

View File

@ -258,7 +258,9 @@ class Solution:
if node.left:
stack.append(node.left)
return result
```
```python
# 中序遍历-迭代-LC94_二叉树的中序遍历
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
@ -279,7 +281,9 @@ class Solution:
# 取栈顶元素右结点
cur = cur.right
return result
```
```python
# 后序遍历-迭代-LC145_二叉树的后序遍历
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:

View File

@ -174,50 +174,49 @@ class Solution {
Python
```python
# 前序遍历-递归-LC144_二叉树的前序遍历
# 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 preorderTraversal(self, root: TreeNode) -> List[int]:
# 保存结果
result = []
def traversal(root: TreeNode):
if root == None:
return
result.append(root.val) # 前序
traversal(root.left) # 左
traversal(root.right) # 右
if not root:
return []
traversal(root)
return result
left = self.preorderTraversal(root.left)
right = self.preorderTraversal(root.right)
return [root.val] + left + right
```
```python
# 中序遍历-递归-LC94_二叉树的中序遍历
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
result = []
if root is None:
return []
def traversal(root: TreeNode):
if root == None:
return
traversal(root.left) # 左
result.append(root.val) # 中序
traversal(root.right) # 右
left = self.inorderTraversal(root.left)
right = self.inorderTraversal(root.right)
return left + [root.val] + right
```
```python
traversal(root)
return result
# 后序遍历-递归-LC145_二叉树的后序遍历
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
result = []
if not root:
return []
def traversal(root: TreeNode):
if root == None:
return
traversal(root.left) # 左
traversal(root.right) # 右
result.append(root.val) # 后序
left = self.postorderTraversal(root.left)
right = self.postorderTraversal(root.right)
traversal(root)
return result
return left + right + [root.val]
```
Go

View File

@ -24,5 +24,5 @@
例如for循环里套一个字符串的inserterase之类的操作你说时间复杂度是多少呢很明显是O(n^2)的时间复杂度了。
在刷题的时候本着我说的标准来使用库函数,详细对大家有所帮助!
在刷题的时候本着我说的标准来使用库函数,相信对大家有所帮助!

View File

@ -266,6 +266,8 @@ func replaceSpace(s string) string {
python
#### 因为字符串是不可变类型所以操作字符串需要将其转换为列表因此空间复杂度不可能为O(1)
(版本一)转换成列表,并且添加相匹配的空间,然后进行填充
```python
class Solution:
def replaceSpace(self, s: str) -> str:
@ -290,14 +292,22 @@ class Solution:
return ''.join(res)
```
(版本二)添加空列表,添加匹配的结果
```python
class Solution:
def replaceSpace(self, s: str) -> str:
res = []
for i in range(len(s)):
if s[i] == ' ':
res.append('%20')
else:
res.append(s[i])
return ''.join(res)
```
(版本三)使用切片
```python
class Solution:
def replaceSpace(self, s: str) -> str:
# method 1 - Very rude
return "%20".join(s.split(" "))
# method 2 - Reverse the s when counting in for loop, then update from the end.
n = len(s)
for e, i in enumerate(s[::-1]):
print(i, e)
@ -306,7 +316,18 @@ class Solution:
print("")
return s
```
版本四使用join + split
```python
class Solution:
def replaceSpace(self, s: str) -> str:
return "%20".join(s.split(" "))
```
版本五使用replace
```python
class Solution:
def replaceSpace(self, s: str) -> str:
return s.replace(' ', '%20')
```
javaScript:
```js

View File

@ -142,15 +142,16 @@ class Solution {
```
python:
(版本一)使用切片
```python
# 方法一:可以使用切片方法
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
return s[n:] + s[0:n]
return s[n:] + s[:n]
```
版本二使用reversed + join
```python
# 方法二:也可以使用上文描述的方法,有些面试中不允许使用切片,那就使用上文作者提到的方法
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
s = list(s)
@ -161,32 +162,29 @@ class Solution:
return "".join(s)
```
版本三自定义reversed函数
```python
# 方法三如果连reversed也不让使用那么自己手写一个
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
def reverse_sub(lst, left, right):
while left < right:
lst[left], lst[right] = lst[right], lst[left]
left += 1
right -= 1
def reverseLeftWords(self, s: str, n: int) -> str:
s_list = list(s)
res = list(s)
end = len(res) - 1
reverse_sub(res, 0, n - 1)
reverse_sub(res, n, end)
reverse_sub(res, 0, end)
return ''.join(res)
self.reverse(s_list, 0, n - 1)
self.reverse(s_list, n, len(s_list) - 1)
self.reverse(s_list, 0, len(s_list) - 1)
# 同方法二
# 时间复杂度O(n)
# 空间复杂度O(n)python的string为不可变需要开辟同样大小的list空间来修改
return ''.join(s_list)
def reverse(self, s, start, end):
while start < end:
s[start], s[end] = s[end], s[start]
start += 1
end -= 1
```
(版本四)使用 模 +下标
```python 3
#方法四:考虑不能用切片的情况下,利用模+下标实现
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
new_s = ''
@ -196,17 +194,21 @@ class Solution:
return new_s
```
(版本五)使用 模 + 切片
```python 3
# 方法五:另类的切片方法
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
n = len(s)
s = s + s
return s[k : n+k]
l = len(s)
# 复制输入字符串与它自己连接
s = s + s
# 计算旋转字符串的起始索引
k = n % (l * 2)
# 从连接的字符串中提取旋转后的字符串并返回
return s[k : k + l]
# 时间复杂度O(n)
# 空间复杂度O(n)
```
Go

View File

@ -10,6 +10,11 @@
<img src='https://code-thinking.cdn.bcebos.com/pics/动态规划-总结大纲1.jpg' width=600> </img>
## 算法公开课
**《代码随想录》算法视频公开课:[动态规划理论基础](https://www.bilibili.com/video/BV13Q4y197Wg),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 什么是动态规划
动态规划英文Dynamic Programming简称DP如果某一问题有很多重叠子问题使用动态规划是最有效的。

View File

@ -573,6 +573,39 @@ object Solution {
}
```
### Rust
```rust
pub struct Solution;
impl Solution {
pub fn wei_bag_problem1(weight: Vec<usize>, value: Vec<usize>, bag_size: usize) -> usize {
let mut dp = vec![vec![0; bag_size + 1]; weight.len()];
for j in weight[0]..=weight.len() {
dp[0][j] = value[0];
}
for i in 1..weight.len() {
for j in 0..=bag_size {
match j < weight[i] {
true => dp[i][j] = dp[i - 1][j],
false => dp[i][j] = dp[i - 1][j].max(dp[i - 1][j - weight[i]] + value[i]),
}
}
}
dp[weight.len() - 1][bag_size]
}
}
#[test]
fn test_wei_bag_problem1() {
println!(
"{}",
Solution::wei_bag_problem1(vec![1, 3, 4], vec![15, 20, 30], 4)
);
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>

View File

@ -406,6 +406,34 @@ object Solution {
}
```
### Rust
```rust
pub struct Solution;
impl Solution {
pub fn wei_bag_problem2(weight: Vec<usize>, value: Vec<usize>, bag_size: usize) -> usize {
let mut dp = vec![0; bag_size + 1];
for i in 0..weight.len() {
for j in (weight[i]..=bag_size).rev() {
if j >= weight[i] {
dp[j] = dp[j].max(dp[j - weight[i]] + value[i]);
}
}
}
dp[dp.len() - 1]
}
}
#[test]
fn test_wei_bag_problem2() {
println!(
"{}",
Solution::wei_bag_problem2(vec![1, 3, 4], vec![15, 20, 30], 4)
);
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>

View File

@ -101,8 +101,8 @@ public:
## 其他语言版本
Java
### Java
```Java
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
@ -150,9 +150,13 @@ public class Solution {
}
```
### Python
Python
```python
版本一求长度同时出发
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
lenA, lenB = 0, 0
@ -178,8 +182,105 @@ class Solution:
curB = curB.next
return None
```
```python
版本二求长度同时出发 代码复用
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
lenA = self.getLength(headA)
lenB = self.getLength(headB)
# 通过移动较长的链表,使两链表长度相等
if lenA > lenB:
headA = self.moveForward(headA, lenA - lenB)
else:
headB = self.moveForward(headB, lenB - lenA)
# 将两个头向前移动,直到它们相交
while headA and headB:
if headA == headB:
return headA
headA = headA.next
headB = headB.next
return None
def getLength(self, head: ListNode) -> int:
length = 0
while head:
length += 1
head = head.next
return length
def moveForward(self, head: ListNode, steps: int) -> ListNode:
while steps > 0:
head = head.next
steps -= 1
return head
```
```python
版本三求长度同时出发 代码复用 + 精简
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
dis = self.getLength(headA) - self.getLength(headB)
# 通过移动较长的链表,使两链表长度相等
if dis > 0:
headA = self.moveForward(headA, dis)
else:
headB = self.moveForward(headB, abs(dis))
# 将两个头向前移动,直到它们相交
while headA and headB:
if headA == headB:
return headA
headA = headA.next
headB = headB.next
return None
def getLength(self, head: ListNode) -> int:
length = 0
while head:
length += 1
head = head.next
return length
def moveForward(self, head: ListNode, steps: int) -> ListNode:
while steps > 0:
head = head.next
steps -= 1
return head
```
```python
版本四等比例法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
### Go
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
# 处理边缘情况
if not headA or not headB:
return None
# 在每个链表的头部初始化两个指针
pointerA = headA
pointerB = headB
# 遍历两个链表直到指针相交
while pointerA != pointerB:
# 将指针向前移动一个节点
pointerA = pointerA.next if pointerA else headB
pointerB = pointerB.next if pointerB else headA
# 如果相交指针将位于交点节点如果没有交点值为None
return pointerA
```
Go:
```go
func getIntersectionNode(headA, headB *ListNode) *ListNode {
@ -240,7 +341,7 @@ func getIntersectionNode(headA, headB *ListNode) *ListNode {
}
```
### javaScript
JavaScript
```js
var getListLen = function(head) {
@ -352,6 +453,7 @@ ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
```
Scala:
```scala
object Solution {
def getIntersectionNode(headA: ListNode, headB: ListNode): ListNode = {