update change
This commit is contained in:
@@ -62,7 +62,7 @@
|
||||
如果你是算法老手,这篇攻略也是复习的最佳资料,如果把每个系列对应的总结篇,快速过一遍,整个算法知识体系以及各种解法就重现脑海了。
|
||||
|
||||
|
||||
目前「代码随想录」刷题攻略更新了:**200多篇文章,精讲了200道经典算法题目,共60w字的详细图解,部分难点题目还搭配了20分钟左右的视频讲解**。
|
||||
目前「代码随想录」刷题攻略更新了:**200多篇文章,精讲了200道经典算法题目,共60w字的详细图解,大部分题目都搭配了20分钟左右的视频讲解**,视频质量很好,口碑很好,大家可以去看看,视频列表:[代码随想录视频讲解](https://www.bilibili.com/video/BV1fA4y1o715)。
|
||||
|
||||
**这里每一篇题解,都是精品,值得仔细琢磨**。
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
# pre,cur,post对应最左,中间的,最右边的节点
|
||||
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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -76,11 +76,9 @@ public:
|
||||
for (int i = 0; i < nums.size(); i++) {
|
||||
nextDistance = max(nums[i] + i, nextDistance); // 更新下一步覆盖最远距离下标
|
||||
if (i == curDistance) { // 遇到当前覆盖最远距离下标
|
||||
if (curDistance < nums.size() - 1) { // 如果当前覆盖最远距离下标不是终点
|
||||
ans++; // 需要走下一步
|
||||
curDistance = nextDistance; // 更新当前覆盖最远距离下标(相当于加油了)
|
||||
if (nextDistance >= nums.size() - 1) break; // 下一步的覆盖范围已经可以达到终点,结束循环
|
||||
} else break; // 当前覆盖最远距到达集合终点,不用做ans++操作了,直接结束
|
||||
ans++; // 需要走下一步
|
||||
curDistance = nextDistance; // 更新当前覆盖最远距离下标(相当于加油了)
|
||||
if (nextDistance >= nums.size() - 1) break; // 当前覆盖最远距到达集合终点,不用做ans++操作了,直接结束
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
@@ -88,6 +86,10 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(n)
|
||||
* 空间复杂度: O(1)
|
||||
|
||||
|
||||
## 方法二
|
||||
|
||||
依然是贪心,思路和方法一差不多,代码可以简洁一些。
|
||||
@@ -127,6 +129,11 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(n)
|
||||
* 空间复杂度: O(1)
|
||||
|
||||
|
||||
|
||||
可以看出版本二的代码相对于版本一简化了不少!
|
||||
|
||||
**其精髓在于控制移动下标 i 只移动到 nums.size() - 2 的位置**,所以移动下标只要遇到当前覆盖最远距离的下标,直接步数加一,不用考虑别的了。
|
||||
@@ -231,6 +238,21 @@ class Solution:
|
||||
step += 1
|
||||
return step
|
||||
```
|
||||
```python
|
||||
# 贪心版本三 - 类似‘55-跳跃游戏’写法
|
||||
class Solution:
|
||||
def jump(self, nums) -> int:
|
||||
if len(nums)==1: return 0
|
||||
i = 0
|
||||
count = 0
|
||||
cover = 0
|
||||
while i<=cover:
|
||||
for i in range(i,cover+1):
|
||||
cover = max(nums[i]+i,cover)
|
||||
if cover>=len(nums)-1: return count+1
|
||||
count+=1
|
||||
|
||||
```
|
||||
|
||||
```python
|
||||
# 动态规划做法
|
||||
|
||||
@@ -158,6 +158,19 @@ if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == true) {
|
||||
|
||||
所以我通过举[1,1,1]的例子,把这两个去重的逻辑分别抽象成树形结构,大家可以一目了然:为什么两种写法都可以以及哪一种效率更高!
|
||||
|
||||
这里可能大家又有疑惑,既然 `used[i - 1] == false`也行而`used[i - 1] == true`也行,那为什么还要写这个条件呢?
|
||||
|
||||
直接这样写 不就完事了?
|
||||
|
||||
```cpp
|
||||
if (i > 0 && nums[i] == nums[i - 1]) {
|
||||
continue;
|
||||
}
|
||||
```
|
||||
|
||||
其实并不行,一定要加上 `used[i - 1] == false`或者`used[i - 1] == true`,因为 used[i - 1] 要一直是 true 或者一直是false 才可以,而不是 一会是true 一会又是false。 所以这个条件要写上。
|
||||
|
||||
|
||||
是不是豁然开朗了!!
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
暴力解法的思路,第一层 for 就是设置起始位置,第二层 for 循环遍历数组寻找最大值
|
||||
|
||||
- 时间复杂度:O(n^2)
|
||||
- 空间复杂度:O(1)
|
||||
|
||||
```CPP
|
||||
class Solution {
|
||||
@@ -44,6 +42,9 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
* 时间复杂度:O(n^2)
|
||||
* 空间复杂度:O(1)
|
||||
|
||||
|
||||
以上暴力的解法 C++勉强可以过,其他语言就不确定了。
|
||||
|
||||
@@ -98,7 +99,6 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
- 时间复杂度:O(n)
|
||||
- 空间复杂度:O(1)
|
||||
|
||||
|
||||
@@ -50,7 +50,8 @@
|
||||
|
||||
如图:
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
i 每次移动只能在 cover 的范围内移动,每移动一个元素,cover 得到该元素数值(新的覆盖范围)的补充,让 i 继续移动下去。
|
||||
|
||||
@@ -75,6 +76,10 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(n)
|
||||
* 空间复杂度: O(1)
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
这道题目关键点在于:不用拘泥于每次究竟跳几步,而是看覆盖范围,覆盖范围内一定是可以跳过来的,不用管是怎么跳的。
|
||||
|
||||
@@ -73,6 +73,10 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(nlogn)
|
||||
* 空间复杂度: O(logn),排序需要的空间开销
|
||||
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
@@ -109,7 +113,6 @@ class Solution {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
```java
|
||||
// 版本2
|
||||
@@ -308,24 +311,22 @@ object Solution {
|
||||
|
||||
```Rust
|
||||
impl Solution {
|
||||
fn max(a: i32, b: i32) -> i32 {
|
||||
if a > b { a } else { b }
|
||||
}
|
||||
|
||||
pub fn merge(intervals: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
|
||||
let mut intervals = intervals;
|
||||
let mut result = Vec::new();
|
||||
if intervals.len() == 0 { return result; }
|
||||
intervals.sort_by(|a, b| a[0].cmp(&b[0]));
|
||||
result.push(intervals[0].clone());
|
||||
for i in 1..intervals.len() {
|
||||
if result.last_mut().unwrap()[1] >= intervals[i][0] {
|
||||
result.last_mut().unwrap()[1] = Self::max(result.last_mut().unwrap()[1], intervals[i][1]);
|
||||
pub fn merge(mut intervals: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
|
||||
let mut res = vec![];
|
||||
if intervals.is_empty() {
|
||||
return res;
|
||||
}
|
||||
intervals.sort_by_key(|a| a[0]);
|
||||
res.push(intervals[0].clone());
|
||||
for interval in intervals.into_iter().skip(1) {
|
||||
let res_last_ele = res.last_mut().unwrap();
|
||||
if res_last_ele[1] >= interval[0] {
|
||||
res_last_ele[1] = interval[1].max(res_last_ele[1]);
|
||||
} else {
|
||||
result.push(intervals[i].clone());
|
||||
res.push(interval);
|
||||
}
|
||||
}
|
||||
result
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -395,21 +395,14 @@ function uniquePaths(m: number, n: number): number {
|
||||
```Rust
|
||||
impl Solution {
|
||||
pub fn unique_paths(m: i32, n: i32) -> i32 {
|
||||
let m = m as usize;
|
||||
let n = n as usize;
|
||||
let mut dp = vec![vec![0; n]; m];
|
||||
for i in 0..m {
|
||||
dp[i][0] = 1;
|
||||
let (m, n) = (m as usize, n as usize);
|
||||
let mut dp = vec![vec![1; n]; m];
|
||||
for i in 1..m {
|
||||
for j in 1..n {
|
||||
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
|
||||
}
|
||||
for j in 0..n {
|
||||
dp[0][j] = 1;
|
||||
}
|
||||
for i in 1..m {
|
||||
for j in 1..n {
|
||||
dp[i][j] = dp[i-1][j] + dp[i][j-1];
|
||||
}
|
||||
}
|
||||
dp[m-1][n-1]
|
||||
}
|
||||
dp[m - 1][n - 1]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -135,7 +135,7 @@ for (int i = 1; i < m; i++) {
|
||||
|
||||

|
||||
|
||||
如果这个图看不同,建议在理解一下递归公式,然后照着文章中说的遍历顺序,自己推导一下!
|
||||
如果这个图看不懂,建议再理解一下递归公式,然后照着文章中说的遍历顺序,自己推导一下!
|
||||
|
||||
动规五部分分析完毕,对应C++代码如下:
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ dp[i]: 爬到第i层楼梯,有dp[i]种方法
|
||||
|
||||
3. dp数组如何初始化
|
||||
|
||||
再回顾一下dp[i]的定义:爬到第i层楼梯,有dp[i]中方法。
|
||||
再回顾一下dp[i]的定义:爬到第i层楼梯,有dp[i]种方法。
|
||||
|
||||
那么i为0,dp[i]应该是多少呢,这个可以有很多解释,但基本都是直接奔着答案去解释的。
|
||||
|
||||
@@ -454,18 +454,32 @@ public class Solution {
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn climb_stairs(n: i32) -> i32 {
|
||||
if n <= 2 {
|
||||
if n <= 1 {
|
||||
return n;
|
||||
}
|
||||
let mut a = 1;
|
||||
let mut b = 2;
|
||||
let mut f = 0;
|
||||
for i in 2..n {
|
||||
let (mut a, mut b, mut f) = (1, 1, 0);
|
||||
for _ in 2..=n {
|
||||
f = a + b;
|
||||
a = b;
|
||||
b = f;
|
||||
}
|
||||
return f;
|
||||
f
|
||||
}
|
||||
```
|
||||
|
||||
dp 数组
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn climb_stairs(n: i32) -> i32 {
|
||||
let n = n as usize;
|
||||
let mut dp = vec![0; n + 1];
|
||||
dp[0] = 1;
|
||||
dp[1] = 1;
|
||||
for i in 2..=n {
|
||||
dp[i] = dp[i - 1] + dp[i - 2];
|
||||
}
|
||||
dp[n]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -101,6 +101,11 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(nm)
|
||||
* 空间复杂度: O(n)
|
||||
|
||||
|
||||
|
||||
代码中m表示最多可以爬m个台阶,代码中把m改成2就是本题70.爬楼梯可以AC的代码了。
|
||||
|
||||
## 总结
|
||||
|
||||
@@ -218,6 +218,10 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
* 时间复杂度: O(n * m)
|
||||
* 空间复杂度: O(n * m)
|
||||
|
||||
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
本题可以使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。
|
||||
|
||||
* 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
|
||||
* 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数后者节点数(取决于高度从0开始还是从1开始)
|
||||
* 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始)
|
||||
|
||||
**而根节点的高度就是二叉树的最大深度**,所以本题中我们通过后序求的根节点高度来求的二叉树最大深度。
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
代码如下:
|
||||
```CPP
|
||||
int getdepth(treenode* node)
|
||||
int getdepth(TreeNode* node)
|
||||
```
|
||||
|
||||
2. 确定终止条件:如果为空节点的话,就返回0,表示高度为0。
|
||||
@@ -76,14 +76,14 @@ return depth;
|
||||
```CPP
|
||||
class solution {
|
||||
public:
|
||||
int getdepth(treenode* node) {
|
||||
int getdepth(TreeNode* node) {
|
||||
if (node == NULL) return 0;
|
||||
int leftdepth = getdepth(node->left); // 左
|
||||
int rightdepth = getdepth(node->right); // 右
|
||||
int depth = 1 + max(leftdepth, rightdepth); // 中
|
||||
return depth;
|
||||
}
|
||||
int maxdepth(treenode* root) {
|
||||
int maxDepth(TreeNode* root) {
|
||||
return getdepth(root);
|
||||
}
|
||||
};
|
||||
@@ -93,9 +93,9 @@ public:
|
||||
```CPP
|
||||
class solution {
|
||||
public:
|
||||
int maxdepth(treenode* root) {
|
||||
int maxDepth(TreeNode* root) {
|
||||
if (root == null) return 0;
|
||||
return 1 + max(maxdepth(root->left), maxdepth(root->right));
|
||||
return 1 + max(maxDepth(root->left), maxDepth(root->right));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
class solution {
|
||||
public:
|
||||
int result;
|
||||
void getdepth(treenode* node, int depth) {
|
||||
void getdepth(TreeNode* node, int depth) {
|
||||
result = depth > result ? depth : result; // 中
|
||||
|
||||
if (node->left == NULL && node->right == NULL) return ;
|
||||
@@ -127,7 +127,7 @@ public:
|
||||
}
|
||||
return ;
|
||||
}
|
||||
int maxdepth(treenode* root) {
|
||||
int maxDepth(TreeNode* root) {
|
||||
result = 0;
|
||||
if (root == NULL) return result;
|
||||
getdepth(root, 1);
|
||||
@@ -144,7 +144,7 @@ public:
|
||||
class solution {
|
||||
public:
|
||||
int result;
|
||||
void getdepth(treenode* node, int depth) {
|
||||
void getdepth(TreeNode* node, int depth) {
|
||||
result = depth > result ? depth : result; // 中
|
||||
if (node->left == NULL && node->right == NULL) return ;
|
||||
if (node->left) { // 左
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
}
|
||||
return ;
|
||||
}
|
||||
int maxdepth(treenode* root) {
|
||||
int maxDepth(TreeNode* root) {
|
||||
result = 0;
|
||||
if (root == 0) return result;
|
||||
getdepth(root, 1);
|
||||
@@ -182,16 +182,16 @@ c++代码如下:
|
||||
```CPP
|
||||
class solution {
|
||||
public:
|
||||
int maxdepth(treenode* root) {
|
||||
int maxDepth(TreeNode* root) {
|
||||
if (root == NULL) return 0;
|
||||
int depth = 0;
|
||||
queue<treenode*> que;
|
||||
queue<TreeNode*> que;
|
||||
que.push(root);
|
||||
while(!que.empty()) {
|
||||
int size = que.size();
|
||||
depth++; // 记录深度
|
||||
for (int i = 0; i < size; i++) {
|
||||
treenode* node = que.front();
|
||||
TreeNode* node = que.front();
|
||||
que.pop();
|
||||
if (node->left) que.push(node->left);
|
||||
if (node->right) que.push(node->right);
|
||||
@@ -230,11 +230,11 @@ c++代码:
|
||||
```CPP
|
||||
class solution {
|
||||
public:
|
||||
int maxdepth(node* root) {
|
||||
int maxDepth(Node* root) {
|
||||
if (root == 0) return 0;
|
||||
int depth = 0;
|
||||
for (int i = 0; i < root->children.size(); i++) {
|
||||
depth = max (depth, maxdepth(root->children[i]));
|
||||
depth = max (depth, maxDepth(root->children[i]));
|
||||
}
|
||||
return depth + 1;
|
||||
}
|
||||
@@ -247,15 +247,15 @@ public:
|
||||
```CPP
|
||||
class solution {
|
||||
public:
|
||||
int maxdepth(node* root) {
|
||||
queue<node*> que;
|
||||
int maxDepth(Node* root) {
|
||||
queue<Node*> que;
|
||||
if (root != NULL) que.push(root);
|
||||
int depth = 0;
|
||||
while (!que.empty()) {
|
||||
int size = que.size();
|
||||
depth++; // 记录深度
|
||||
for (int i = 0; i < size; i++) {
|
||||
node* node = que.front();
|
||||
Node* node = que.front();
|
||||
que.pop();
|
||||
for (int j = 0; j < node->children.size(); j++) {
|
||||
if (node->children[j]) que.push(node->children[j]);
|
||||
@@ -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
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -622,7 +622,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
|
||||
|
||||
@@ -170,11 +170,14 @@ class Solution {
|
||||
private:
|
||||
int result;
|
||||
void getdepth(TreeNode* node, int depth) {
|
||||
if (node->left == NULL && node->right == NULL) {
|
||||
result = min(depth, result);
|
||||
// 函数递归终止条件
|
||||
if (root == nullptr) {
|
||||
return;
|
||||
}
|
||||
// 中 只不过中没有处理的逻辑
|
||||
// 中,处理逻辑:判断是不是叶子结点
|
||||
if (root -> left == nullptr && root->right == nullptr) {
|
||||
res = min(res, depth);
|
||||
}
|
||||
if (node->left) { // 左
|
||||
getdepth(node->left, depth + 1);
|
||||
}
|
||||
@@ -186,7 +189,9 @@ private:
|
||||
|
||||
public:
|
||||
int minDepth(TreeNode* root) {
|
||||
if (root == NULL) return 0;
|
||||
if (root == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
result = INT_MAX;
|
||||
getdepth(root, 1);
|
||||
return result;
|
||||
@@ -300,46 +305,98 @@ 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 minDepth(self, root: TreeNode) -> int:
|
||||
if not root:
|
||||
return 0
|
||||
|
||||
if not root.left and not root.right:
|
||||
return 1
|
||||
|
||||
min_depth = 10**9
|
||||
|
||||
left_depth = float('inf')
|
||||
right_depth = float('inf')
|
||||
|
||||
if root.left:
|
||||
min_depth = min(self.minDepth(root.left), min_depth) # 获得左子树的最小高度
|
||||
left_depth = self.minDepth(root.left)
|
||||
if root.right:
|
||||
min_depth = min(self.minDepth(root.right), min_depth) # 获得右子树的最小高度
|
||||
return min_depth + 1
|
||||
right_depth = self.minDepth(root.right)
|
||||
|
||||
return 1 + min(left_depth, right_depth)
|
||||
|
||||
```
|
||||
|
||||
迭代法:
|
||||
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
class Solution:
|
||||
def minDepth(self, root: TreeNode) -> int:
|
||||
if not root:
|
||||
return 0
|
||||
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
|
||||
```
|
||||
|
||||
迭代法:
|
||||
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
|
||||
class Solution:
|
||||
def minDepth(self, root: TreeNode) -> int:
|
||||
if not root:
|
||||
return 0
|
||||
|
||||
queue = collections.deque([(root, 1)])
|
||||
|
||||
while queue:
|
||||
node, depth = queue.popleft()
|
||||
|
||||
# Check if the node is a leaf node
|
||||
if not node.left and not node.right:
|
||||
return depth
|
||||
|
||||
# Add left and right child to the queue
|
||||
if node.left:
|
||||
queue.append((node.left, depth+1))
|
||||
if node.right:
|
||||
queue.append((node.right, depth+1))
|
||||
|
||||
return 0
|
||||
|
||||
```
|
||||
|
||||
## Go
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
示例:
|
||||
给定如下二叉树,以及目标和 sum = 22,
|
||||
|
||||

|
||||

|
||||
|
||||
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
|
||||
|
||||
@@ -250,7 +250,7 @@ private:
|
||||
vector<vector<int>> result;
|
||||
vector<int> path;
|
||||
// 递归函数不需要返回值,因为我们要遍历整个树
|
||||
void traversal(treenode* cur, int count) {
|
||||
void traversal(TreeNode* cur, int count) {
|
||||
if (!cur->left && !cur->right && count == 0) { // 遇到了叶子节点且找到了和为sum的路径
|
||||
result.push_back(path);
|
||||
return;
|
||||
@@ -276,10 +276,10 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
vector<vector<int>> pathsum(treenode* root, int sum) {
|
||||
vector<vector<int>> pathSum(TreeNode* root, int sum) {
|
||||
result.clear();
|
||||
path.clear();
|
||||
if (root == null) return result;
|
||||
if (root == NULL) return result;
|
||||
path.push_back(root->val); // 把根节点放进路径
|
||||
traversal(root, sum - root->val);
|
||||
return result;
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -149,6 +149,11 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(n * m)
|
||||
* 空间复杂度: O(n * m)
|
||||
|
||||
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
|
||||
@@ -289,7 +289,45 @@ class Solution:
|
||||
## Go
|
||||
|
||||
```go
|
||||
func minCut(s string) int {
|
||||
isValid := make([][]bool, len(s))
|
||||
for i := 0; i < len(isValid); i++ {
|
||||
isValid[i] = make([]bool, len(s))
|
||||
isValid[i][i] = true
|
||||
}
|
||||
for i := len(s) - 1; i >= 0; i-- {
|
||||
for j := i + 1; j < len(s); j++ {
|
||||
if s[i] == s[j] && (isValid[i + 1][j - 1] || j - i == 1) {
|
||||
isValid[i][j] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dp := make([]int, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
dp[i] = math.MaxInt
|
||||
}
|
||||
for i := 0; i < len(s); i++ {
|
||||
if isValid[0][i] {
|
||||
dp[i] = 0
|
||||
continue
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
if isValid[j + 1][i] {
|
||||
dp[i] = min(dp[i], dp[j] + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[len(s) - 1]
|
||||
}
|
||||
|
||||
func min(i, j int) int {
|
||||
if i < j {
|
||||
return i
|
||||
} else {
|
||||
return j
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## JavaScript
|
||||
|
||||
@@ -121,6 +121,11 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(n)
|
||||
* 空间复杂度: O(n)
|
||||
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
这在leetcode上是一道困难的题目,其难点就在于贪心的策略,如果在考虑局部的时候想两边兼顾,就会顾此失彼。
|
||||
|
||||
@@ -351,7 +351,17 @@ class Solution:
|
||||
dp[j] = dp[j] or (dp[j - len(word)] and word == s[j - len(word):j])
|
||||
return dp[len(s)]
|
||||
```
|
||||
|
||||
```python
|
||||
class Solution: # 和视频中写法一致(和最上面C++写法一致)
|
||||
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
|
||||
dp = [False]*(len(s)+1)
|
||||
dp[0]=True
|
||||
for j in range(1,len(s)+1):
|
||||
for i in range(j):
|
||||
word = s[i:j]
|
||||
if word in wordDict and dp[i]: dp[j]=True
|
||||
return dp[-1]
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -970,6 +970,49 @@ pub fn remove_extra_spaces(s: &mut Vec<char>) {
|
||||
}
|
||||
}
|
||||
```
|
||||
C:
|
||||
|
||||
```C
|
||||
// 翻转字符串中指定范围的字符
|
||||
void reverse(char* s, int start, int end) {
|
||||
for (int i = start, j = end; i < j; i++, j--) {
|
||||
int tmp = s[i];
|
||||
s[i] = s[j];
|
||||
s[j] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// 删除字符串两端和中间多余的空格
|
||||
void removeExtraSpace(char* s) {
|
||||
int start = 0; // 指向字符串开头的指针
|
||||
int end = strlen(s) - 1; // 指向字符串结尾的指针
|
||||
while (s[start] == ' ') start++; // 移动指针 start,直到找到第一个非空格字符
|
||||
while (s[end] == ' ') end--; // 移动指针 end,直到找到第一个非空格字符
|
||||
int slow = 0; // 指向新字符串的下一个写入位置的指针
|
||||
for (int i = start; i <= end; i++) { // 遍历整个字符串
|
||||
if (s[i] == ' ' && s[i+1] == ' ') { // 如果当前字符是空格,并且下一个字符也是空格,则跳过
|
||||
continue;
|
||||
}
|
||||
s[slow] = s[i]; // 否则,将当前字符复制到新字符串的 slow 位置
|
||||
slow++; // 将 slow 指针向后移动
|
||||
}
|
||||
s[slow] = '\0'; // 在新字符串的末尾添加一个空字符
|
||||
}
|
||||
|
||||
// 翻转字符串中的单词
|
||||
char * reverseWords(char * s){
|
||||
removeExtraSpace(s); // 先删除字符串两端和中间的多余空格
|
||||
reverse(s, 0, strlen(s) - 1); // 翻转整个字符串
|
||||
int slow = 0; // 指向每个单词的开头位置的指针
|
||||
for (int i = 0; i <= strlen(s); i++) { // 遍历整个字符串
|
||||
if (s[i] ==' ' || s[i] == '\0') { // 如果当前字符是空格或空字符,说明一个单词结束了
|
||||
reverse(s, slow, i-1); // 翻转单词
|
||||
slow = i + 1; // 将 slow 指针指向下一个单词的开头位置
|
||||
}
|
||||
}
|
||||
return s; // 返回处理后的字符串
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
|
||||
@@ -156,6 +156,11 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(n * k),其中 n 为 prices 的长度
|
||||
* 空间复杂度: O(n * k)
|
||||
|
||||
|
||||
|
||||
当然有的解法是定义一个三维数组dp[i][j][k],第i天,第j次买卖,k表示买还是卖的状态,从定义上来讲是比较直观。
|
||||
|
||||
但感觉三维数组操作起来有些麻烦,我是直接用二维数组来模拟三维数组的情况,代码看起来也清爽一些。
|
||||
@@ -323,6 +328,42 @@ func max(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
版本二: 三维 dp数组
|
||||
```go
|
||||
func maxProfit(k int, prices []int) int {
|
||||
length := len(prices)
|
||||
if length == 0 {
|
||||
return 0
|
||||
}
|
||||
// [天数][交易次数][是否持有股票]
|
||||
// 1表示不持有/卖出, 0表示持有/买入
|
||||
dp := make([][][]int, length)
|
||||
for i := 0; i < length; i++ {
|
||||
dp[i] = make([][]int, k+1)
|
||||
for j := 0; j <= k; j++ {
|
||||
dp[i][j] = make([]int, 2)
|
||||
}
|
||||
}
|
||||
for j := 0; j <= k; j++ {
|
||||
dp[0][j][0] = -prices[0]
|
||||
}
|
||||
for i := 1; i < length; i++ {
|
||||
for j := 1; j <= k; j++ {
|
||||
dp[i][j][0] = max188(dp[i-1][j][0], dp[i-1][j-1][1]-prices[i])
|
||||
dp[i][j][1] = max188(dp[i-1][j][1], dp[i-1][j][0]+prices[i])
|
||||
}
|
||||
}
|
||||
return dp[length-1][k][1]
|
||||
}
|
||||
|
||||
func max188(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
```
|
||||
|
||||
Javascript:
|
||||
|
||||
```javascript
|
||||
|
||||
@@ -108,6 +108,9 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(n)
|
||||
* 空间复杂度: O(n)
|
||||
|
||||
## 总结
|
||||
|
||||
打家劫舍是DP解决的经典题目,这道题也是打家劫舍入门级题目,后面我们还会变种方式来打劫的。
|
||||
@@ -150,7 +153,17 @@ class Solution:
|
||||
dp[i] = max(dp[i-2]+nums[i], dp[i-1])
|
||||
return dp[-1]
|
||||
```
|
||||
|
||||
```python
|
||||
class Solution: # 二维dp数组写法
|
||||
def rob(self, nums: List[int]) -> int:
|
||||
dp = [[0,0] for _ in range(len(nums))]
|
||||
dp[0][1] = nums[0]
|
||||
for i in range(1,len(nums)):
|
||||
dp[i][0] = max(dp[i-1][1],dp[i-1][0])
|
||||
dp[i][1] = dp[i-1][0]+nums[i]
|
||||
print(dp)
|
||||
return max(dp[-1])
|
||||
```
|
||||
Go:
|
||||
```Go
|
||||
func rob(nums []int) int {
|
||||
|
||||
@@ -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!=None):
|
||||
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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -82,6 +82,11 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(n)
|
||||
* 空间复杂度: O(n)
|
||||
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
成环之后还是难了一些的, 不少题解没有把“考虑房间”和“偷房间”说清楚。
|
||||
@@ -142,7 +147,20 @@ class Solution:
|
||||
dp[i]=max(dp[i-1],dp[i-2]+nums[i])
|
||||
return dp[-1]
|
||||
```
|
||||
|
||||
```python
|
||||
class Solution: # 二维dp数组写法
|
||||
def rob(self, nums: List[int]) -> int:
|
||||
if len(nums)<3: return max(nums)
|
||||
return max(self.default(nums[:-1]),self.default(nums[1:]))
|
||||
def default(self,nums):
|
||||
dp = [[0,0] for _ in range(len(nums))]
|
||||
dp[0][1] = nums[0]
|
||||
for i in range(1,len(nums)):
|
||||
dp[i][0] = max(dp[i-1])
|
||||
dp[i][1] = dp[i-1][0] + nums[i]
|
||||
return max(dp[-1])
|
||||
|
||||
```
|
||||
Go:
|
||||
|
||||
```go
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
递归版本的前序遍历
|
||||
|
||||
@@ -205,6 +205,19 @@ var isAnagram = function(s, t) {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var isAnagram = function(s, t) {
|
||||
if(s.length !== t.length) return false;
|
||||
let char_count = new Map();
|
||||
for(let item of s) {
|
||||
char_count.set(item, (char_count.get(item) || 0) + 1) ;
|
||||
}
|
||||
for(let item of t) {
|
||||
if(!char_count.get(item)) return false;
|
||||
char_count.set(item, char_count.get(item)-1);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
@@ -127,6 +127,10 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(n * √n)
|
||||
* 空间复杂度: O(n)
|
||||
|
||||
|
||||
同样我在给出先遍历物品,在遍历背包的代码,一样的可以AC的。
|
||||
|
||||
```CPP
|
||||
@@ -145,6 +149,8 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
* 同上
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
|
||||
@@ -106,6 +106,10 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
* 时间复杂度: O(n^2)
|
||||
* 空间复杂度: O(n)
|
||||
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
|
||||
@@ -133,6 +133,11 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(n * amount),其中 n 为 coins 的长度
|
||||
* 空间复杂度: O(amount)
|
||||
|
||||
|
||||
|
||||
对于遍历方式遍历背包放在外循环,遍历物品放在内循环也是可以的,我就直接给出代码了
|
||||
|
||||
```CPP
|
||||
@@ -154,6 +159,8 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
* 同上
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
|
||||
@@ -380,7 +380,33 @@ class Solution:
|
||||
backtracking("JFK")
|
||||
return path
|
||||
```
|
||||
|
||||
python - 使用used数组 - 神似之前几题写法
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
|
||||
global used,path,results
|
||||
used = [0]*len(tickets)
|
||||
path = ['JFK']
|
||||
results = []
|
||||
tickets.sort() # 先排序,这样一旦找到第一个可行路径,一定是字母排序最小的
|
||||
self.backtracking(tickets,'JFK')
|
||||
return results[0]
|
||||
def backtracking(self,tickets,cur):
|
||||
if sum(used) == len(tickets):
|
||||
results.append(path[:])
|
||||
return True # 只要找到就返回
|
||||
for i in range(len(tickets)):
|
||||
if tickets[i][0]==cur and used[i]==0:
|
||||
used[i]=1
|
||||
path.append(tickets[i][1])
|
||||
state = self.backtracking(tickets,tickets[i][1])
|
||||
path.pop()
|
||||
used[i]=0
|
||||
if state: return True # 只要找到就返回,不继续搜索了
|
||||
```
|
||||
|
||||
### GO
|
||||
```go
|
||||
type pair struct {
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
### 情况二:数组首尾两端
|
||||
|
||||
所以本题统计峰值的时候,数组最左面和最右面如果统计呢?
|
||||
所以本题统计峰值的时候,数组最左面和最右面如何统计呢?
|
||||
|
||||
题目中说了,如果只有两个不同的元素,那摆动序列也是 2。
|
||||
|
||||
@@ -655,3 +655,4 @@ object Solution {
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
# 完全背包的排列问题模拟
|
||||
|
||||
#### Problem
|
||||
|
||||
1. 排列问题是完全背包中十分棘手的问题。
|
||||
2. 其在迭代过程中需要先迭代背包容量,再迭代物品个数,使得其在代码理解上较难入手。
|
||||
|
||||
#### Contribution
|
||||
|
||||
本文档以力扣上[组合总和IV](https://leetcode.cn/problems/combination-sum-iv/)为例,提供一个二维dp的代码例子,并提供模拟过程以便于理解
|
||||
|
||||
#### Code
|
||||
|
||||
```cpp
|
||||
int combinationSum4(vector<int>& nums, int target) {
|
||||
// 定义背包容量为target,物品个数为nums.size()的dp数组
|
||||
// dp[i][j]表示将第0-i个物品添加入排列中,和为j的排列方式
|
||||
vector<vector<int>> dp (nums.size(), vector(target+1,0));
|
||||
|
||||
// 表示有0,1,...,n个物品可选择的情况下,和为0的选择方法为1:什么都不取
|
||||
for(int i = 0; i < nums.size(); i++) dp[i][0] = 1;
|
||||
|
||||
// 必须按列遍历,因为右边数组需要知道左边数组最低部的信息(排列问题)
|
||||
// 后面的模拟可以更清楚的表现这么操作的原因
|
||||
for(int i = 1; i <= target; i++){
|
||||
for(int j = 0; j < nums.size(); j++){
|
||||
// 只有nums[j]可以取的情况
|
||||
if(j == 0){
|
||||
if(nums[j] > i) dp[j][i] = 0;
|
||||
// 如果背包容量放不下 那么此时没有排列方式
|
||||
else dp[j][i] = dp[nums.size()-1][i-nums[j]];
|
||||
// 如果背包容量放的下 全排列方式为dp[最底层][容量-该物品容量]排列方式后面放一个nums[j]
|
||||
}
|
||||
// 有多个nums数可以取
|
||||
else{
|
||||
// 如果背包容量放不下 那么沿用0-j-1个物品的排列方式
|
||||
if(nums[j] > i) dp[j][i] = dp[j-1][i];
|
||||
// 如果背包容量放得下 在dp[最底层][容量-该物品容量]排列方式后面放一个nums[j]后面放个nums[j]
|
||||
// INT_MAX避免溢出
|
||||
else if(i >= nums[j] && dp[j-1][i] < INT_MAX - dp[nums.size()-1][i-nums[j]])
|
||||
dp[j][i] = dp[j-1][i] + dp[nums.size()-1][i-nums[j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
// 打印dp数组
|
||||
for(int i = 0; i < nums.size(); i++){
|
||||
for(int j = 0; j <= target; j++){
|
||||
cout<<dp[i][j]<<" ";
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
return dp[nums.size()-1][target];
|
||||
}
|
||||
```
|
||||
|
||||
#### Simulation
|
||||
|
||||
##### 样例 nums = [2,3,4], target = 6
|
||||
|
||||
##### 1. 初始化一个3x7的dp数组
|
||||
|
||||
1 0 0 0 0 0 0
|
||||
1 0 0 0 0 0 0
|
||||
1 0 0 0 0 0 0
|
||||
|
||||
dp\[0-2\]\[0\] = 1,含义是有nums[0-2]物品时使得背包容量为0的取法为1,作用是在取到nums[i]物品使得背包容量为nums[i]时取法为1。
|
||||
|
||||
##### 2.迭代方式
|
||||
|
||||
必须列优先,因为右边的数组在迭代时需要最左下的数组最终结果。
|
||||
|
||||
##### 3. 模拟过程
|
||||
|
||||
i = 1, j = 0 dp\[0\]\[1\] = 0,表示在物品集合{2}中无法组成和为1
|
||||
i = 1, j = 1 dp\[1\]\[1\] = 0,表示在物品集合{2,3}中无法组成和为1
|
||||
i = 1, j = 2 dp\[2\]\[1\] = 0,表示在物品集合{2,3,4}中无法组成和为1
|
||||
|
||||
1 0 0 0 0 0 0
|
||||
1 0 0 0 0 0 0
|
||||
1 **0** 0 0 0 0 0
|
||||
|
||||
此时dp\[2\]\[1\]作为第1列最底部的元素,表示所有物品都有的情况下组成和为1的排列方式为0
|
||||
|
||||
————————————————————————————
|
||||
|
||||
i = 2, j = 0 dp\[0\]\[2\] = 1,表示在物品集合{2}中取出和为2的排列有{2}
|
||||
i = 2, j = 1 dp\[1\]\[2\] = 1,表示在物品集合{2,3}中取出和为2的排列有{2}
|
||||
i = 2, j = 2 dp\[2\]\[2\] = 1,表示在物品集合{2,3,4}中取出和为2的排列有{2}
|
||||
|
||||
1 0 1 0 0 0 0
|
||||
1 0 1 0 0 0 0
|
||||
1 0 **1** 0 0 0 0
|
||||
|
||||
此时dp\[2\]\[2\]作为第2列最底部的元素,表示所有物品都有的情况下和为2的排列方式有1个 (类比成一维dp即dp[2]=dp[0])
|
||||
|
||||
————————————————————————————
|
||||
|
||||
i = 3, j = 0 dp\[0\]\[3\] = 0,表示在物品集合{2}中无法取出和为3
|
||||
i = 3, j = 1 dp\[1\]\[3\] = 1,表示在物品集合{2,3}中取出和为3的排列有{3}
|
||||
i = 3, j = 2 dp\[2\]\[3\] = 1,表示在物品集合{2,3,4}中取出和为3的排列有{3}
|
||||
|
||||
1 0 1 0 0 0 0
|
||||
1 0 1 1 0 0 0
|
||||
1 0 1 **1** 0 0 0
|
||||
|
||||
此时dp\[2\]\[3\]作为第3列最底部的元素,表示所有物品都有的情况下和为3的排列方式有1个(类比成一维dp即dp[3]=dp[0])
|
||||
|
||||
————————————————————————————
|
||||
|
||||
i = 4, j = 0 dp\[0\]\[4\] = 1,表示在物品集合{2}中取出和为4的排列有在原有的排列{2}后添加一个2成为{2,2}(从第2列底部信息继承获得)
|
||||
i = 4, j = 1 dp\[1\]\[4\] = 1,表示在物品集合{2,3}中取出和为4的排列有{2,2}
|
||||
i = 4, j = 2 dp\[2\]\[4\] = 2,表示在物品集合{2,3,4}中取出和为4的排列有{{2,2},{4}}({2,2}的信息从该列头上获得)
|
||||
|
||||
1 0 1 0 1 0 0
|
||||
1 0 1 1 1 0 0
|
||||
1 0 1 1 **2** 0 0
|
||||
|
||||
此时dp\[2\]\[4\]作为第4列最底部的元素,表示所有物品都有的情况下和为4的排列方式有2个
|
||||
|
||||
————————————————————————————
|
||||
|
||||
i = 5, j = 0 dp\[0\]\[5\] = 1,表示在物品集合{2}中取出和为5的排列有{3,2} **(3的信息由dp[2]\[3]获得,即将2放在3的右边)**
|
||||
i = 5, j = 1 dp\[1\]\[5\] = 2,表示在物品集合{2,3}中取出和为5的排列有{{2,3},{3,2}} **({3,2}由上一行信息继承,{2,3}是从dp[2] [2]获得,将3放在2的右边)**
|
||||
i = 5, j = 2 dp\[2\]\[5\] = 2,表示在物品集合{2,3,4}中取出和为5的排列有{{2,3},{3,2}}
|
||||
|
||||
1 0 1 0 1 1 0
|
||||
1 0 1 1 1 2 0
|
||||
1 0 1 1 2 **2** 0
|
||||
|
||||
此时dp\[2\]\[5\]作为第5列最底部的元素,表示所有物品都有的情况下和为5的排列方式有2个
|
||||
|
||||
————————————————————————————
|
||||
|
||||
i = 6, j = 0 dp\[0\]\[6\] = 2,表示在物品集合{2}中取出和为6的排列有{{2,2,2},{4,2}} **(信息由dp[2]\[4]获得,即将2放在{2,2}和{4}的右边)**
|
||||
i = 6, j = 1 dp\[1\]\[6\] = 3,表示在物品集合{2,3}中取出和为6的排列有{{2,2,2},{4,2},{3,3}} **({2,2,2},{4,2}由上一行信息继承,{3,3}是从dp[2] [3]获得,将3放在3的右边)**
|
||||
i = 6, j = 2 dp\[2\]\[6\] = 4,表示在物品集合{2,3,4}中取出和为6的排列有{{2,2,2},{4,2},{3,3},{2,4}} **({2,2,2},{4,2},{3,3}由上一行继承,{2,4}从dp[2]获得,将4放在2的右边)**
|
||||
|
||||
1 0 1 0 1 1 2
|
||||
1 0 1 1 1 2 3
|
||||
1 0 1 1 2 2 **4**
|
||||
|
||||
此时dp\[2\]\[6\]作为第6列最底部的元素,表示所有物品都有的情况下和为6的排列方式有4个,为{2,2,2},{4,2},{3,3},{2,4}。
|
||||
|
||||
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
# 完全背包的排列问题模拟
|
||||
|
||||
#### Problem
|
||||
|
||||
1. 排列问题是完全背包中十分棘手的问题。
|
||||
2. 其在迭代过程中需要先迭代背包容量,再迭代物品个数,使得其在代码理解上较难入手。
|
||||
|
||||
#### Contribution
|
||||
|
||||
本文档以力扣上[组合总和IV](https://leetcode.cn/problems/combination-sum-iv/)为例,提供一个二维dp的代码例子,并提供模拟过程以便于理解
|
||||
|
||||
#### Code
|
||||
|
||||
```cpp
|
||||
int combinationSum4(vector<int>& nums, int target) {
|
||||
// 定义背包容量为target,物品个数为nums.size()的dp数组
|
||||
// dp[i][j]表示将第0-i个物品添加入排列中,和为j的排列方式
|
||||
vector<vector<int>> dp (nums.size(), vector(target+1,0));
|
||||
|
||||
// 表示有0,1,...,n个物品可选择的情况下,和为0的选择方法为1:什么都不取
|
||||
for(int i = 0; i < nums.size(); i++) dp[i][0] = 1;
|
||||
|
||||
// 必须按列遍历,因为右边数组需要知道左边数组最低部的信息(排列问题)
|
||||
// 后面的模拟可以更清楚的表现这么操作的原因
|
||||
for(int i = 1; i <= target; i++){
|
||||
for(int j = 0; j < nums.size(); j++){
|
||||
// 只有nums[j]可以取的情况
|
||||
if(j == 0){
|
||||
if(nums[j] > i) dp[j][i] = 0;
|
||||
// 如果背包容量放不下 那么此时没有排列方式
|
||||
else dp[j][i] = dp[nums.size()-1][i-nums[j]];
|
||||
// 如果背包容量放的下 全排列方式为dp[最底层][容量-该物品容量]排列方式后面放一个nums[j]
|
||||
}
|
||||
// 有多个nums数可以取
|
||||
else{
|
||||
// 如果背包容量放不下 那么沿用0-j-1个物品的排列方式
|
||||
if(nums[j] > i) dp[j][i] = dp[j-1][i];
|
||||
// 如果背包容量放得下 在dp[最底层][容量-该物品容量]排列方式后面放一个nums[j]后面放个nums[j]
|
||||
// INT_MAX避免溢出
|
||||
else if(i >= nums[j] && dp[j-1][i] < INT_MAX - dp[nums.size()-1][i-nums[j]])
|
||||
dp[j][i] = dp[j-1][i] + dp[nums.size()-1][i-nums[j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
// 打印dp数组
|
||||
for(int i = 0; i < nums.size(); i++){
|
||||
for(int j = 0; j <= target; j++){
|
||||
cout<<dp[i][j]<<" ";
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
return dp[nums.size()-1][target];
|
||||
}
|
||||
```
|
||||
|
||||
#### Simulation
|
||||
|
||||
##### 样例 nums = [2,3,4], target = 6
|
||||
|
||||
##### 1. 初始化一个3x7的dp数组
|
||||
|
||||
1 0 0 0 0 0 0
|
||||
1 0 0 0 0 0 0
|
||||
1 0 0 0 0 0 0
|
||||
|
||||
dp\[0-2\]\[0\] = 1,含义是有nums[0-2]物品时使得背包容量为0的取法为1,作用是在取到nums[i]物品使得背包容量为nums[i]时取法为1。
|
||||
|
||||
##### 2.迭代方式
|
||||
|
||||
必须列优先,因为右边的数组在迭代时需要最左下的数组最终结果。
|
||||
|
||||
##### 3. 模拟过程
|
||||
|
||||
i = 1, j = 0 dp\[0\]\[1\] = 0,表示在物品集合{2}中无法组成和为1
|
||||
i = 1, j = 1 dp\[1\]\[1\] = 0,表示在物品集合{2,3}中无法组成和为1
|
||||
i = 1, j = 2 dp\[2\]\[1\] = 0,表示在物品集合{2,3,4}中无法组成和为1
|
||||
|
||||
1 0 0 0 0 0 0
|
||||
1 0 0 0 0 0 0
|
||||
1 **0** 0 0 0 0 0
|
||||
|
||||
此时dp\[2\]\[1\]作为第1列最底部的元素,表示所有物品都有的情况下组成和为1的排列方式为0
|
||||
|
||||
————————————————————————————
|
||||
|
||||
i = 2, j = 0 dp\[0\]\[2\] = 1,表示在物品集合{2}中取出和为2的排列有{2}
|
||||
i = 2, j = 1 dp\[1\]\[2\] = 1,表示在物品集合{2,3}中取出和为2的排列有{2}
|
||||
i = 2, j = 2 dp\[2\]\[2\] = 1,表示在物品集合{2,3,4}中取出和为2的排列有{2}
|
||||
|
||||
1 0 1 0 0 0 0
|
||||
1 0 1 0 0 0 0
|
||||
1 0 **1** 0 0 0 0
|
||||
|
||||
此时dp\[2\]\[2\]作为第2列最底部的元素,表示所有物品都有的情况下和为2的排列方式有1个 (类比成一维dp即dp[2]=dp[0])
|
||||
|
||||
————————————————————————————
|
||||
|
||||
i = 3, j = 0 dp\[0\]\[3\] = 0,表示在物品集合{2}中无法取出和为3
|
||||
i = 3, j = 1 dp\[1\]\[3\] = 1,表示在物品集合{2,3}中取出和为3的排列有{3}
|
||||
i = 3, j = 2 dp\[2\]\[3\] = 1,表示在物品集合{2,3,4}中取出和为3的排列有{3}
|
||||
|
||||
1 0 1 0 0 0 0
|
||||
1 0 1 1 0 0 0
|
||||
1 0 1 **1** 0 0 0
|
||||
|
||||
此时dp\[2\]\[3\]作为第3列最底部的元素,表示所有物品都有的情况下和为3的排列方式有1个(类比成一维dp即dp[3]=dp[0])
|
||||
|
||||
————————————————————————————
|
||||
|
||||
i = 4, j = 0 dp\[0\]\[4\] = 1,表示在物品集合{2}中取出和为4的排列有在原有的排列{2}后添加一个2成为{2,2}(从第2列底部信息继承获得)
|
||||
i = 4, j = 1 dp\[1\]\[4\] = 1,表示在物品集合{2,3}中取出和为4的排列有{2,2}
|
||||
i = 4, j = 2 dp\[2\]\[4\] = 2,表示在物品集合{2,3,4}中取出和为4的排列有{{2,2},{4}}({2,2}的信息从该列头上获得)
|
||||
|
||||
1 0 1 0 1 0 0
|
||||
1 0 1 1 1 0 0
|
||||
1 0 1 1 **2** 0 0
|
||||
|
||||
此时dp\[2\]\[4\]作为第4列最底部的元素,表示所有物品都有的情况下和为4的排列方式有2个
|
||||
|
||||
————————————————————————————
|
||||
|
||||
i = 5, j = 0 dp\[0\]\[5\] = 1,表示在物品集合{2}中取出和为5的排列有{3,2} **(3的信息由dp[2]\[3]获得,即将2放在3的右边)**
|
||||
i = 5, j = 1 dp\[1\]\[5\] = 2,表示在物品集合{2,3}中取出和为5的排列有{{2,3},{3,2}} **({3,2}由上一行信息继承,{2,3}是从dp[2] [2]获得,将3放在2的右边)**
|
||||
i = 5, j = 2 dp\[2\]\[5\] = 2,表示在物品集合{2,3,4}中取出和为5的排列有{{2,3},{3,2}}
|
||||
|
||||
1 0 1 0 1 1 0
|
||||
1 0 1 1 1 2 0
|
||||
1 0 1 1 2 **2** 0
|
||||
|
||||
此时dp\[2\]\[5\]作为第5列最底部的元素,表示所有物品都有的情况下和为5的排列方式有2个
|
||||
|
||||
————————————————————————————
|
||||
|
||||
i = 6, j = 0 dp\[0\]\[6\] = 2,表示在物品集合{2}中取出和为6的排列有{{2,2,2},{4,2}} **(信息由dp[2]\[4]获得,即将2放在{2,2}和{4}的右边)**
|
||||
i = 6, j = 1 dp\[1\]\[6\] = 3,表示在物品集合{2,3}中取出和为6的排列有{{2,2,2},{4,2},{3,3}} **({2,2,2},{4,2}由上一行信息继承,{3,3}是从dp[2] [3]获得,将3放在3的右边)**
|
||||
i = 6, j = 2 dp\[2\]\[6\] = 4,表示在物品集合{2,3,4}中取出和为6的排列有{{2,2,2},{4,2},{3,3},{2,4}} **({2,2,2},{4,2},{3,3}由上一行继承,{2,4}从dp[2]获得,将4放在2的右边)**
|
||||
|
||||
1 0 1 0 1 1 2
|
||||
1 0 1 1 1 2 3
|
||||
1 0 1 1 2 2 **4**
|
||||
|
||||
此时dp\[2\]\[6\]作为第6列最底部的元素,表示所有物品都有的情况下和为6的排列方式有4个,为{2,2,2},{4,2},{3,3},{2,4}。
|
||||
|
||||
|
||||
|
||||
@@ -130,6 +130,11 @@ public:
|
||||
|
||||
```
|
||||
|
||||
* 时间复杂度: O(target * n),其中 n 为 nums 的长度
|
||||
* 空间复杂度: O(target)
|
||||
|
||||
|
||||
|
||||
C++测试用例有两个数相加超过int的数据,所以需要在if里加上dp[i] < INT_MAX - dp[i - num]。
|
||||
|
||||
但java就不用考虑这个限制,java里的int也是四个字节吧,也有可能leetcode后台对不同语言的测试数据不一样。
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -399,18 +399,20 @@ object Solution {
|
||||
```Rust
|
||||
impl Solution {
|
||||
pub fn erase_overlap_intervals(intervals: Vec<Vec<i32>>) -> i32 {
|
||||
if intervals.len() == 0 { return 0; }
|
||||
let mut intervals = intervals;
|
||||
intervals.sort_by(|a, b| a[1].cmp(&b[1]));
|
||||
if intervals.is_empty() {
|
||||
return 0;
|
||||
}
|
||||
intervals.sort_by_key(|interval| interval[1]);
|
||||
let mut count = 1;
|
||||
let mut end = intervals[0][1];
|
||||
for i in 1..intervals.len() {
|
||||
if end <= intervals[i][0] {
|
||||
end = intervals[i][1];
|
||||
for v in intervals.iter().skip(1) {
|
||||
if end <= v[0] {
|
||||
end = v[1];
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
intervals.len() as i32 - count
|
||||
|
||||
(intervals.len() - count) as i32
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -177,7 +177,23 @@ class Solution:
|
||||
points[i][1] = min(points[i - 1][1], points[i][1]) # 更新重叠气球最小右边界
|
||||
return result
|
||||
```
|
||||
```python
|
||||
class Solution: # 不改变原数组
|
||||
def findMinArrowShots(self, points: List[List[int]]) -> int:
|
||||
points.sort(key = lambda x: x[0])
|
||||
sl,sr = points[0][0],points[0][1]
|
||||
count = 1
|
||||
for i in points:
|
||||
if i[0]>sr:
|
||||
count+=1
|
||||
sl,sr = i[0],i[1]
|
||||
else:
|
||||
sl = max(sl,i[0])
|
||||
sr = min(sr,i[1])
|
||||
return count
|
||||
|
||||
|
||||
```
|
||||
### Go
|
||||
```go
|
||||
func findMinArrowShots(points [][]int) int {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
如图:
|
||||
|
||||

|
||||

|
||||
|
||||
这个例子可以看出饼干 9 只有喂给胃口为 7 的小孩,这样才是整体最优解,并想不出反例,那么就可以撸代码了。
|
||||
|
||||
@@ -56,8 +56,6 @@ C++代码整体如下:
|
||||
|
||||
```CPP
|
||||
// 版本一
|
||||
// 时间复杂度:O(nlogn)
|
||||
// 空间复杂度:O(1)
|
||||
class Solution {
|
||||
public:
|
||||
int findContentChildren(vector<int>& g, vector<int>& s) {
|
||||
@@ -75,6 +73,9 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
* 时间复杂度:O(nlogn)
|
||||
* 空间复杂度:O(1)
|
||||
|
||||
|
||||
从代码中可以看出我用了一个 index 来控制饼干数组的遍历,遍历饼干并没有再起一个 for 循环,而是采用自减的方式,这也是常用的技巧。
|
||||
|
||||
@@ -118,6 +119,9 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
* 时间复杂度:O(nlogn)
|
||||
* 空间复杂度:O(1)
|
||||
|
||||
|
||||
细心的录友可以发现,这种写法,两个循环的顺序改变了,先遍历的饼干,在遍历的胃口,这是因为遍历顺序变了,我们是从小到大遍历。
|
||||
|
||||
|
||||
@@ -156,6 +156,11 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(kmn),k 为strs的长度
|
||||
* 空间复杂度: O(mn)
|
||||
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
不少同学刷过这道题,可能没有总结这究竟是什么背包。
|
||||
|
||||
@@ -347,26 +347,32 @@ int fib(int n){
|
||||
### Rust
|
||||
动态规划:
|
||||
```Rust
|
||||
pub fn fib(n: i32) -> i32 {
|
||||
let n = n as usize;
|
||||
let mut dp = vec![0; 31];
|
||||
dp[1] = 1;
|
||||
for i in 2..=n {
|
||||
dp[i] = dp[i - 1] + dp[i - 2];
|
||||
impl Solution {
|
||||
pub fn fib(n: i32) -> i32 {
|
||||
if n <= 1 {
|
||||
return n;
|
||||
}
|
||||
let n = n as usize;
|
||||
let mut dp = vec![0; n + 1];
|
||||
dp[1] = 1;
|
||||
for i in 2..=n {
|
||||
dp[i] = dp[i - 2] + dp[i - 1];
|
||||
}
|
||||
dp[n]
|
||||
}
|
||||
dp[n]
|
||||
}
|
||||
```
|
||||
|
||||
递归实现:
|
||||
```Rust
|
||||
pub fn fib(n: i32) -> i32 {
|
||||
//若n小于等于1,返回n
|
||||
f n <= 1 {
|
||||
return n;
|
||||
impl Solution {
|
||||
pub fn fib(n: i32) -> i32 {
|
||||
if n <= 1 {
|
||||
n
|
||||
} else {
|
||||
Self::fib(n - 1) + Self::fib(n - 2)
|
||||
}
|
||||
}
|
||||
//否则返回fib(n-1) + fib(n-2)
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -144,6 +144,11 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
* 时间复杂度: O(n^2)
|
||||
* 空间复杂度: O(n^2)
|
||||
|
||||
|
||||
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
@@ -179,6 +179,11 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(mn),其中 m 是amount,n 是 coins 的长度
|
||||
* 空间复杂度: O(m)
|
||||
|
||||
|
||||
是不是发现代码如此精简,哈哈
|
||||
|
||||
## 总结
|
||||
@@ -215,6 +220,27 @@ class Solution {
|
||||
}
|
||||
}
|
||||
```
|
||||
```Java
|
||||
// 二维dp数组版本,方便理解
|
||||
class Solution {
|
||||
public int change(int amount, int[] coins) {
|
||||
int[][] dp = new int[coins.length][amount + 1];
|
||||
// 只有一种硬币的情况
|
||||
for (int i = 0; i <= amount; i += coins[0]) {
|
||||
dp[0][i] = 1;
|
||||
}
|
||||
for (int i = 1; i < coins.length; i++) {
|
||||
for (int j = 0; j <= amount; j++) {
|
||||
// 第i种硬币使用0~k次,求和
|
||||
for (int k = 0; k * coins[i] <= j; k++) {
|
||||
dp[i][j] += dp[i - 1][j - k * coins[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[coins.length - 1][amount];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
|
||||
@@ -234,6 +234,26 @@ class Solution:
|
||||
return root
|
||||
|
||||
```
|
||||
**迭代**
|
||||
```python
|
||||
class Solution:
|
||||
def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
|
||||
if not root: return root
|
||||
stack = []
|
||||
result = []
|
||||
cur = root
|
||||
pre = 0
|
||||
while cur or stack:
|
||||
if cur:
|
||||
stack.append(cur)
|
||||
cur = cur.right
|
||||
else:
|
||||
cur = stack.pop()
|
||||
cur.val+= pre
|
||||
pre = cur.val
|
||||
cur =cur.left
|
||||
return root
|
||||
```
|
||||
|
||||
## Go
|
||||
|
||||
|
||||
@@ -104,6 +104,10 @@ public:
|
||||
};
|
||||
|
||||
```
|
||||
* 时间复杂度: O(n * m)
|
||||
* 空间复杂度: O(n * m)
|
||||
|
||||
|
||||
|
||||
### 动态规划二
|
||||
|
||||
@@ -127,6 +131,10 @@ public:
|
||||
};
|
||||
|
||||
```
|
||||
* 时间复杂度: O(n * m)
|
||||
* 空间复杂度: O(n * m)
|
||||
|
||||
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
@@ -267,6 +267,27 @@ class Solution {
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
动态规划:简洁版
|
||||
```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 res;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
中心扩散法:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -280,18 +280,20 @@ object Solution {
|
||||
```Rust
|
||||
impl Solution {
|
||||
pub fn monotone_increasing_digits(n: i32) -> i32 {
|
||||
let mut str_num = n.to_string().chars().map(|x| x.to_digit(10).unwrap() as i32).collect::<Vec<i32>>();
|
||||
let mut flag = str_num.len();
|
||||
for i in (1..str_num.len()).rev() {
|
||||
if str_num[i - 1] > str_num[i] {
|
||||
let mut n_bytes = n.to_string().into_bytes();
|
||||
let mut flag = n_bytes.len();
|
||||
for i in (1..n_bytes.len()).rev() {
|
||||
if n_bytes[i - 1] > n_bytes[i] {
|
||||
flag = i;
|
||||
str_num[i - 1] -= 1;
|
||||
n_bytes[i - 1] -= 1;
|
||||
}
|
||||
}
|
||||
for i in flag..str_num.len() {
|
||||
str_num[i] = 9;
|
||||
for v in n_bytes.iter_mut().skip(flag) {
|
||||
*v = 57;
|
||||
}
|
||||
str_num.iter().fold(0, |acc, x| acc * 10 + x)
|
||||
n_bytes
|
||||
.into_iter()
|
||||
.fold(0, |acc, x| acc * 10 + x as i32 - 48)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -271,6 +271,7 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
> 未精简版本
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
@@ -291,6 +292,21 @@ class Solution:
|
||||
return answer
|
||||
```
|
||||
|
||||
> 精简版本
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
|
||||
answer = [0]*len(temperatures)
|
||||
stack = []
|
||||
for i in range(len(temperatures)):
|
||||
while len(stack)>0 and temperatures[i] > temperatures[stack[-1]]:
|
||||
answer[stack[-1]] = i - stack[-1]
|
||||
stack.pop()
|
||||
stack.append(i)
|
||||
return answer
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
> 暴力法
|
||||
|
||||
@@ -92,7 +92,7 @@ dp[i - 2] 跳到 dp[i] 需要花费 dp[i - 2] + cost[i - 2]。
|
||||
|
||||
这里就要说明本题力扣为什么改题意,而且修改题意之后 就清晰很多的原因了。
|
||||
|
||||
新题目描述中明确说了 “你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。” 也就是说 从 到达 第 0 个台阶是不花费的,但从 第0 个台阶 往上跳的话,需要花费 cost[0]。
|
||||
新题目描述中明确说了 “你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。” 也就是说 到达 第 0 个台阶是不花费的,但从 第0 个台阶 往上跳的话,需要花费 cost[0]。
|
||||
|
||||
所以初始化 dp[0] = 0,dp[1] = 0;
|
||||
|
||||
@@ -312,17 +312,30 @@ func min(a, b int) int {
|
||||
```
|
||||
|
||||
|
||||
### Javascript
|
||||
```Javascript
|
||||
### JavaScript
|
||||
|
||||
```JavaScript
|
||||
var minCostClimbingStairs = function(cost) {
|
||||
const n = cost.length;
|
||||
const dp = new Array(n + 1);
|
||||
dp[0] = dp[1] = 0;
|
||||
for (let i = 2; i <= n; ++i) {
|
||||
dp[i] = Math.min(dp[i -1] + cost[i - 1], dp[i - 2] + cost[i - 2])
|
||||
const dp = [0, 0]
|
||||
for (let i = 2; i <= cost.length; ++i) {
|
||||
dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2])
|
||||
}
|
||||
return dp[cost.length]
|
||||
};
|
||||
```
|
||||
|
||||
不使用 dp 数组
|
||||
|
||||
```JavaScript
|
||||
var minCostClimbingStairs = function(cost) {
|
||||
let dpBefore = 0,
|
||||
dpAfter = 0
|
||||
for(let i = 2;i <= cost.length;i++){
|
||||
let dpi = Math.min(dpBefore + cost[i - 2],dpAfter + cost[i - 1])
|
||||
dpBefore = dpAfter
|
||||
dpAfter = dpi
|
||||
}
|
||||
|
||||
return dp[n]
|
||||
return dpAfter
|
||||
};
|
||||
```
|
||||
|
||||
@@ -330,38 +343,55 @@ var minCostClimbingStairs = function(cost) {
|
||||
|
||||
```typescript
|
||||
function minCostClimbingStairs(cost: number[]): number {
|
||||
/**
|
||||
dp[i]: 走到第i阶需要花费的最少金钱
|
||||
dp[0]: 0;
|
||||
dp[1]: 0;
|
||||
...
|
||||
dp[i]: min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
|
||||
*/
|
||||
const dp = [];
|
||||
const length = cost.length;
|
||||
dp[0] = 0;
|
||||
dp[1] = 0;
|
||||
for (let i = 2; i <= length; i++) {
|
||||
dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
|
||||
}
|
||||
return dp[length];
|
||||
};
|
||||
const dp = [0, 0]
|
||||
for (let i = 2; i <= cost.length; i++) {
|
||||
dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2])
|
||||
}
|
||||
return dp[cost.length]
|
||||
}
|
||||
```
|
||||
|
||||
不使用 dp 数组
|
||||
|
||||
```typescript
|
||||
function minCostClimbingStairs(cost: number[]): number {
|
||||
let dpBefore = 0,
|
||||
dpAfter = 0
|
||||
for (let i = 2; i <= cost.length; i++) {
|
||||
let dpi = Math.min(dpBefore + cost[i - 2], dpAfter + cost[i - 1])
|
||||
dpBefore = dpAfter
|
||||
dpAfter = dpi
|
||||
}
|
||||
return dpAfter
|
||||
}
|
||||
```
|
||||
|
||||
### Rust
|
||||
|
||||
```Rust
|
||||
use std::cmp::min;
|
||||
impl Solution {
|
||||
pub fn min_cost_climbing_stairs(cost: Vec<i32>) -> i32 {
|
||||
let len = cost.len();
|
||||
let mut dp = vec![0; len];
|
||||
dp[0] = cost[0];
|
||||
dp[1] = cost[1];
|
||||
for i in 2..len {
|
||||
dp[i] = min(dp[i-1], dp[i-2]) + cost[i];
|
||||
let mut dp = vec![0; cost.len() + 1];
|
||||
for i in 2..=cost.len() {
|
||||
dp[i] = (dp[i - 1] + cost[i - 1]).min(dp[i - 2] + cost[i - 2]);
|
||||
}
|
||||
min(dp[len-1], dp[len-2])
|
||||
dp[cost.len()]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
不使用 dp 数组
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn min_cost_climbing_stairs(cost: Vec<i32>) -> i32 {
|
||||
let (mut dp_before, mut dp_after) = (0, 0);
|
||||
for i in 2..=cost.len() {
|
||||
let dpi = (dp_before + cost[i - 2]).min(dp_after + cost[i - 1]);
|
||||
dp_before = dp_after;
|
||||
dp_after = dpi;
|
||||
}
|
||||
dp_after
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -369,18 +399,29 @@ impl Solution {
|
||||
### C
|
||||
|
||||
```c
|
||||
int minCostClimbingStairs(int* cost, int costSize){
|
||||
//开辟dp数组,大小为costSize
|
||||
int *dp = (int *)malloc(sizeof(int) * costSize);
|
||||
//初始化dp[0] = cost[0], dp[1] = cost[1]
|
||||
dp[0] = cost[0], dp[1] = cost[1];
|
||||
#include <math.h>
|
||||
int minCostClimbingStairs(int *cost, int costSize) {
|
||||
int dp[costSize + 1];
|
||||
dp[0] = dp[1] = 0;
|
||||
for (int i = 2; i <= costSize; i++) {
|
||||
dp[i] = fmin(dp[i - 2] + cost[i - 2], dp[i - 1] + cost[i - 1]);
|
||||
}
|
||||
return dp[costSize];
|
||||
}
|
||||
```
|
||||
|
||||
int i;
|
||||
for(i = 2; i < costSize; ++i) {
|
||||
dp[i] = (dp[i-1] < dp[i-2] ? dp[i-1] : dp[i-2]) + cost[i];
|
||||
}
|
||||
//选出倒数2层楼梯中较小的
|
||||
return dp[i-1] < dp[i-2] ? dp[i-1] : dp[i-2];
|
||||
不使用 dp 数组
|
||||
|
||||
```c
|
||||
#include <math.h>
|
||||
int minCostClimbingStairs(int *cost, int costSize) {
|
||||
int dpBefore = 0, dpAfter = 0;
|
||||
for (int i = 2; i <= costSize; i++) {
|
||||
int dpi = fmin(dpBefore + cost[i - 2], dpAfter + cost[i - 1]);
|
||||
dpBefore = dpAfter;
|
||||
dpAfter = dpi;
|
||||
}
|
||||
return dpAfter;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -412,28 +412,22 @@ object Solution {
|
||||
### Rust
|
||||
|
||||
```Rust
|
||||
use std::collections::HashMap;
|
||||
impl Solution {
|
||||
fn max (a: usize, b: usize) -> usize {
|
||||
if a > b { a } else { b }
|
||||
}
|
||||
pub fn partition_labels(s: String) -> Vec<i32> {
|
||||
let s = s.chars().collect::<Vec<char>>();
|
||||
let mut hash: HashMap<char, usize> = HashMap::new();
|
||||
for i in 0..s.len() {
|
||||
hash.insert(s[i], i);
|
||||
let mut hash = vec![0; 26];
|
||||
for (i, &c) in s.as_bytes().iter().enumerate() {
|
||||
hash[(c - b'a') as usize] = i;
|
||||
}
|
||||
let mut result: Vec<i32> = Vec::new();
|
||||
let mut left: usize = 0;
|
||||
let mut right: usize = 0;
|
||||
for i in 0..s.len() {
|
||||
right = Self::max(right, hash[&s[i]]);
|
||||
let mut res = vec![];
|
||||
let (mut left, mut right) = (0, 0);
|
||||
for (i, &c) in s.as_bytes().iter().enumerate() {
|
||||
right = right.max(hash[(c - b'a') as usize]);
|
||||
if i == right {
|
||||
result.push((right - left + 1) as i32);
|
||||
res.push((right - left + 1) as i32);
|
||||
left = i + 1;
|
||||
}
|
||||
}
|
||||
result
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -535,8 +535,57 @@ function getIndexAfterDel(s: string, startIndex: number): number {
|
||||
}
|
||||
```
|
||||
|
||||
### Rust
|
||||
|
||||
> 双指针
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn backspace_compare(s: String, t: String) -> bool {
|
||||
let (s, t) = (
|
||||
s.chars().collect::<Vec<char>>(),
|
||||
t.chars().collect::<Vec<char>>(),
|
||||
);
|
||||
Self::get_string(s) == Self::get_string(t)
|
||||
}
|
||||
|
||||
pub fn get_string(mut chars: Vec<char>) -> Vec<char> {
|
||||
let mut slow = 0;
|
||||
for i in 0..chars.len() {
|
||||
if chars[i] == '#' {
|
||||
slow = (slow as u32).saturating_sub(1) as usize;
|
||||
} else {
|
||||
chars[slow] = chars[i];
|
||||
slow += 1;
|
||||
}
|
||||
}
|
||||
chars.truncate(slow);
|
||||
chars
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 双栈法
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn backspace_compare(s: String, t: String) -> bool {
|
||||
Self::get_string(s) == Self::get_string(t)
|
||||
}
|
||||
|
||||
pub fn get_string(string: String) -> String {
|
||||
let mut s = String::new();
|
||||
for c in string.chars() {
|
||||
if c != '#' {
|
||||
s.push(c);
|
||||
} else if !s.is_empty() {
|
||||
s.pop();
|
||||
}
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
|
||||
@@ -115,6 +115,9 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
* 时间复杂度: O(n)
|
||||
* 空间复杂度: O(1)
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
|
||||
@@ -303,6 +303,11 @@ public:
|
||||
|
||||
```
|
||||
|
||||
* 时间复杂度: O(n),需要遍历二叉树上的每个节点
|
||||
* 空间复杂度: O(n)
|
||||
|
||||
|
||||
|
||||
大家可能会惊讶,居然可以这么简短,**其实就是在版本一的基础上,使用else把一些情况直接覆盖掉了**。
|
||||
|
||||
在网上关于这道题解可以搜到很多这种神级别的代码,但都没讲不清楚,如果直接看代码的话,指定越看越晕,**所以建议大家对着版本一的代码一步一步来,版本二中看不中用!**。
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -252,6 +252,36 @@ var commonChars = function (words) {
|
||||
}
|
||||
return res
|
||||
};
|
||||
|
||||
// 方法二:map()
|
||||
var commonChars = function(words) {
|
||||
let min_count = new Map()
|
||||
// 统计字符串中字符出现的最小频率,以第一个字符串初始化
|
||||
for(let str of words[0]) {
|
||||
min_count.set(str, ((min_count.get(str) || 0) + 1))
|
||||
}
|
||||
// 从第二个单词开始统计字符出现次数
|
||||
for(let i = 1; i < words.length; i++) {
|
||||
let char_count = new Map()
|
||||
for(let str of words[i]) { // 遍历字母
|
||||
char_count.set(str, (char_count.get(str) || 0) + 1)
|
||||
}
|
||||
// 比较出最小的字符次数
|
||||
for(let value of min_count) { // 注意这里遍历min_count!而不是单词
|
||||
min_count.set(value[0], Math.min((min_count.get(value[0]) || 0), (char_count.get(value[0]) || 0)))
|
||||
}
|
||||
}
|
||||
// 遍历map
|
||||
let res = []
|
||||
min_count.forEach((value, key) => {
|
||||
if(value) {
|
||||
for(let i=0; i<value; i++) {
|
||||
res.push(key)
|
||||
}
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
TypeScript
|
||||
|
||||
@@ -85,6 +85,10 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度: O(nlogn)
|
||||
* 空间复杂度: O(1)
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
贪心的题目如果简单起来,会让人简单到开始怀疑:本来不就应该这么做么?这也算是算法?我认为这不是贪心?
|
||||
|
||||
@@ -62,6 +62,10 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
* 时间复杂度: O(n * m)
|
||||
* 空间复杂度: O(n * m)
|
||||
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
|
||||
@@ -124,6 +124,10 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
* 时间复杂度: O(n * m),其中 n 和 m 分别为 text1 和 text2 的长度
|
||||
* 空间复杂度: O(n * m)
|
||||
|
||||
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
@@ -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]:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -24,5 +24,5 @@
|
||||
|
||||
例如for循环里套一个字符串的insert,erase之类的操作,你说时间复杂度是多少呢,很明显是O(n^2)的时间复杂度了。
|
||||
|
||||
在刷题的时候本着我说的标准来使用库函数,详细对大家回有所帮助!
|
||||
在刷题的时候本着我说的标准来使用库函数,相信对大家会有所帮助!
|
||||
|
||||
|
||||
@@ -54,9 +54,9 @@ int function2(int x, int n) {
|
||||
|
||||
```CPP
|
||||
int function3(int x, int n) {
|
||||
if (n == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (n == 0) return 1;
|
||||
if (n == 1) return x;
|
||||
|
||||
if (n % 2 == 1) {
|
||||
return function3(x, n / 2) * function3(x, n / 2)*x;
|
||||
}
|
||||
@@ -93,9 +93,8 @@ int function3(int x, int n) {
|
||||
|
||||
```CPP
|
||||
int function4(int x, int n) {
|
||||
if (n == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (n == 0) return 1;
|
||||
if (n == 1) return x;
|
||||
int t = function4(x, n / 2);// 这里相对于function3,是把这个递归操作抽取出来
|
||||
if (n % 2 == 1) {
|
||||
return t * t * x;
|
||||
@@ -124,9 +123,8 @@ int function4(int x, int n) {
|
||||
|
||||
```CPP
|
||||
int function3(int x, int n) {
|
||||
if (n == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (n == 0) return 1;
|
||||
if (n == 1) return x;
|
||||
if (n % 2 == 1) {
|
||||
return function3(x, n / 2) * function3(x, n / 2)*x;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ public:
|
||||
|
||||
**这也体现了刷题顺序的重要性**。
|
||||
|
||||
先遍历背包,在遍历物品:
|
||||
先遍历背包,再遍历物品:
|
||||
|
||||
```CPP
|
||||
// 版本一
|
||||
@@ -165,7 +165,7 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
先遍历物品,在遍历背包:
|
||||
先遍历物品,再遍历背包:
|
||||
|
||||
```CPP
|
||||
// 版本二
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
在C++中,set 和 map 分别提供以下三种数据结构,其底层实现以及优劣如下表所示:
|
||||
|
||||
| 集合 | 底层实现 | 是否有序 | 数值是否可以重复 | 能否更改数值 | 查询效率 | 增删效率 |
|
||||
| ------------------ | -------- | -------- | ---------------- | ------------ | -------- | -------- |
|
||||
| --- | --- | ---- | --- | --- | --- | --- |
|
||||
| std::set | 红黑树 | 有序 | 否 | 否 | O(log n) | O(log n) |
|
||||
| std::multiset | 红黑树 | 有序 | 是 | 否 | O(logn) | O(logn) |
|
||||
| std::unordered_set | 哈希表 | 无序 | 否 | 否 | O(1) | O(1) |
|
||||
@@ -97,11 +97,12 @@
|
||||
std::unordered_set底层实现为哈希表,std::set 和std::multiset 的底层实现是红黑树,红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。
|
||||
|
||||
| 映射 | 底层实现 | 是否有序 | 数值是否可以重复 | 能否更改数值 | 查询效率 | 增删效率 |
|
||||
| ------------------ | -------- | -------- | ---------------- | ------------ | -------- | -------- |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| std::map | 红黑树 | key有序 | key不可重复 | key不可修改 | O(logn) | O(logn) |
|
||||
| std::multimap | 红黑树 | key有序 | key可重复 | key不可修改 | O(log n) | O(log n) |
|
||||
| std::unordered_map | 哈希表 | key无序 | key不可重复 | key不可修改 | O(1) | O(1) |
|
||||
|
||||
|
||||
std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树。同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解)。
|
||||
|
||||
当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的,如果需要集合是有序的,那么就用set,如果要求不仅有序还要有重复数据的话,那么就用multiset。
|
||||
|
||||
@@ -177,6 +177,35 @@ Java:
|
||||
|
||||
Python:
|
||||
|
||||
Rust:
|
||||
|
||||
```rust
|
||||
// 版本二,使用list(链表)
|
||||
use std::collections::LinkedList;
|
||||
impl Solution{
|
||||
pub fn reconstruct_queue(mut people: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
|
||||
let mut queue = LinkedList::new();
|
||||
people.sort_by(|a, b| {
|
||||
if a[0] == b[0] {
|
||||
return a[1].cmp(&b[1]);
|
||||
}
|
||||
b[0].cmp(&a[0])
|
||||
});
|
||||
queue.push_back(people[0].clone());
|
||||
for v in people.iter().skip(1) {
|
||||
if queue.len() > v[1] as usize {
|
||||
let mut back_link = queue.split_off(v[1] as usize);
|
||||
queue.push_back(v.clone());
|
||||
queue.append(&mut back_link);
|
||||
} else {
|
||||
queue.push_back(v.clone());
|
||||
}
|
||||
}
|
||||
queue.into_iter().collect()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Go:
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
* [动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html)
|
||||
* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)
|
||||
|
||||
首先在回顾一下01背包的核心代码
|
||||
首先再回顾一下01背包的核心代码
|
||||
```cpp
|
||||
for(int i = 0; i < weight.size(); i++) { // 遍历物品
|
||||
for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
|
||||
@@ -173,7 +173,7 @@ int main() {
|
||||
|
||||
别急,下一篇就是了!哈哈
|
||||
|
||||
最后,**又可以出一道面试题了,就是纯完全背包,要求先用二维dp数组实现,然后再用一维dp数组实现,最后在问,两个for循环的先后是否可以颠倒?为什么?**
|
||||
最后,**又可以出一道面试题了,就是纯完全背包,要求先用二维dp数组实现,然后再用一维dp数组实现,最后再问,两个for循环的先后是否可以颠倒?为什么?**
|
||||
这个简单的完全背包问题,估计就可以难住不少候选人了。
|
||||
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ public class Solution {
|
||||
|
||||
### Python
|
||||
```python
|
||||
|
||||
(版本一)求长度,同时出发
|
||||
class Solution:
|
||||
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
|
||||
lenA, lenB = 0, 0
|
||||
@@ -178,7 +178,68 @@ 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
|
||||
(版本三)等比例法
|
||||
# Definition for singly-linked list.
|
||||
# class ListNode:
|
||||
# def __init__(self, x):
|
||||
# self.val = x
|
||||
# self.next = None
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user