mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-08 16:54:50 +08:00
Merge branch 'youngyangyang04:master' into master
This commit is contained in:
@ -112,8 +112,8 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n\log n)$ ,有一个快排
|
* 时间复杂度:O(nlog n) ,有一个快排
|
||||||
* 空间复杂度:$O(1)$,我没有算result数组(返回值所需容器占的空间)
|
* 空间复杂度:O(n),有一个快排,最差情况(倒序)时,需要n次递归调用。因此确实需要O(n)的栈空间
|
||||||
|
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
也可以直接看我的B站视频:[带你学透回溯算法-组合问题(对应力扣题目:77.组合)](https://www.bilibili.com/video/BV1ti4y1L7cv#reply3733925949)
|
也可以直接看我的B站视频:[带你学透回溯算法-组合问题(对应力扣题目:77.组合)](https://www.bilibili.com/video/BV1ti4y1L7cv#reply3733925949)
|
||||||
|
|
||||||
# 思路
|
## 思路
|
||||||
|
|
||||||
|
|
||||||
本题这是回溯法的经典题目。
|
本题这是回溯法的经典题目。
|
||||||
@ -232,7 +232,7 @@ void backtracking(参数) {
|
|||||||
|
|
||||||
**对比一下本题的代码,是不是发现有点像!** 所以有了这个模板,就有解题的大体方向,不至于毫无头绪。
|
**对比一下本题的代码,是不是发现有点像!** 所以有了这个模板,就有解题的大体方向,不至于毫无头绪。
|
||||||
|
|
||||||
# 总结
|
## 总结
|
||||||
|
|
||||||
组合问题是回溯法解决的经典问题,我们开始的时候给大家列举一个很形象的例子,就是n为100,k为50的话,直接想法就需要50层for循环。
|
组合问题是回溯法解决的经典问题,我们开始的时候给大家列举一个很形象的例子,就是n为100,k为50的话,直接想法就需要50层for循环。
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ void backtracking(参数) {
|
|||||||
|
|
||||||
接着用回溯法三部曲,逐步分析了函数参数、终止条件和单层搜索的过程。
|
接着用回溯法三部曲,逐步分析了函数参数、终止条件和单层搜索的过程。
|
||||||
|
|
||||||
# 剪枝优化
|
## 剪枝优化
|
||||||
|
|
||||||
我们说过,回溯法虽然是暴力搜索,但也有时候可以有点剪枝优化一下的。
|
我们说过,回溯法虽然是暴力搜索,但也有时候可以有点剪枝优化一下的。
|
||||||
|
|
||||||
@ -324,7 +324,7 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
# 剪枝总结
|
## 剪枝总结
|
||||||
|
|
||||||
本篇我们准对求组合问题的回溯法代码做了剪枝优化,这个优化如果不画图的话,其实不好理解,也不好讲清楚。
|
本篇我们准对求组合问题的回溯法代码做了剪枝优化,这个优化如果不画图的话,其实不好理解,也不好讲清楚。
|
||||||
|
|
||||||
@ -334,10 +334,10 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
## Java:
|
### Java:
|
||||||
```java
|
```java
|
||||||
class Solution {
|
class Solution {
|
||||||
List<List<Integer>> result = new ArrayList<>();
|
List<List<Integer>> result = new ArrayList<>();
|
||||||
@ -366,6 +366,8 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Python
|
||||||
|
|
||||||
Python2:
|
Python2:
|
||||||
```python
|
```python
|
||||||
class Solution(object):
|
class Solution(object):
|
||||||
@ -395,7 +397,6 @@ class Solution(object):
|
|||||||
return result
|
return result
|
||||||
```
|
```
|
||||||
|
|
||||||
## Python
|
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def combine(self, n: int, k: int) -> List[List[int]]:
|
def combine(self, n: int, k: int) -> List[List[int]]:
|
||||||
@ -432,7 +433,7 @@ class Solution:
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## javascript
|
### javascript
|
||||||
|
|
||||||
剪枝:
|
剪枝:
|
||||||
```javascript
|
```javascript
|
||||||
@ -456,7 +457,7 @@ const combineHelper = (n, k, startIndex) => {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## TypeScript
|
### TypeScript
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
function combine(n: number, k: number): number[][] {
|
function combine(n: number, k: number): number[][] {
|
||||||
@ -479,7 +480,7 @@ function combine(n: number, k: number): number[][] {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Go
|
### Go
|
||||||
```Go
|
```Go
|
||||||
var res [][]int
|
var res [][]int
|
||||||
func combine(n int, k int) [][]int {
|
func combine(n int, k int) [][]int {
|
||||||
@ -534,7 +535,7 @@ func backtrack(n,k,start int,track []int){
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## C
|
### C
|
||||||
```c
|
```c
|
||||||
int* path;
|
int* path;
|
||||||
int pathTop;
|
int pathTop;
|
||||||
@ -642,7 +643,7 @@ int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Swift
|
### Swift
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func combine(_ n: Int, _ k: Int) -> [[Int]] {
|
func combine(_ n: Int, _ k: Int) -> [[Int]] {
|
||||||
|
@ -238,7 +238,7 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
# 总结
|
## 总结
|
||||||
|
|
||||||
这次我们又深度剖析了一道二叉树的“简单题”,大家会发现,真正的把题目搞清楚其实并不简单,leetcode上accept了和真正掌握了还是有距离的。
|
这次我们又深度剖析了一道二叉树的“简单题”,大家会发现,真正的把题目搞清楚其实并不简单,leetcode上accept了和真正掌握了还是有距离的。
|
||||||
|
|
||||||
@ -248,7 +248,7 @@ public:
|
|||||||
|
|
||||||
如果已经做过这道题目的同学,读完文章可以再去看看这道题目,思考一下,会有不一样的发现!
|
如果已经做过这道题目的同学,读完文章可以再去看看这道题目,思考一下,会有不一样的发现!
|
||||||
|
|
||||||
# 相关题目推荐
|
## 相关题目推荐
|
||||||
|
|
||||||
这两道题目基本和本题是一样的,只要稍加修改就可以AC。
|
这两道题目基本和本题是一样的,只要稍加修改就可以AC。
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
* 时间复杂度:O(nlog n) ,有一个快排
|
* 时间复杂度:O(nlog n) ,有一个快排
|
||||||
* 空间复杂度:O(1)
|
* 空间复杂度:O(n),有一个快排,最差情况(倒序)时,需要n次递归调用。因此确实需要O(n)的栈空间
|
||||||
|
|
||||||
大家此时会发现如此复杂的一个问题,代码实现却这么简单!
|
大家此时会发现如此复杂的一个问题,代码实现却这么简单!
|
||||||
|
|
||||||
|
@ -105,8 +105,8 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n\log n)$,因为有一个快排
|
* 时间复杂度:O(nlog n),因为有一个快排
|
||||||
* 空间复杂度:$O(1)$
|
* 空间复杂度:O(1),有一个快排,最差情况(倒序)时,需要n次递归调用。因此确实需要O(n)的栈空间
|
||||||
|
|
||||||
可以看出代码并不复杂。
|
可以看出代码并不复杂。
|
||||||
|
|
||||||
|
@ -315,6 +315,30 @@ function test () {
|
|||||||
test();
|
test();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function testWeightBagProblem(
|
||||||
|
weight: number[],
|
||||||
|
value: number[],
|
||||||
|
size: number
|
||||||
|
): number {
|
||||||
|
const goodsNum: number = weight.length;
|
||||||
|
const dp: number[] = new Array(size + 1).fill(0);
|
||||||
|
for (let i = 0; i < goodsNum; i++) {
|
||||||
|
for (let j = size; j >= weight[i]; j--) {
|
||||||
|
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[size];
|
||||||
|
}
|
||||||
|
const weight = [1, 3, 4];
|
||||||
|
const value = [15, 20, 30];
|
||||||
|
const size = 4;
|
||||||
|
console.log(testWeightBagProblem(weight, value, size));
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
# 双指针,不计算链表长度
|
|
||||||
设置指向headA和headB的指针pa、pb,分别遍历两个链表,每次循环同时更新pa和pb。
|
|
||||||
* 当链表A遍历完之后,即pa为空时,将pa指向headB;
|
|
||||||
* 当链表B遍历完之后,即pa为空时,将pb指向headA;
|
|
||||||
* 当pa与pb相等时,即指向同一个节点,该节点即为相交起始节点。
|
|
||||||
* 若链表不相交,则pa、pb同时为空时退出循环,即如果链表不相交,pa与pb在遍历过全部节点后同时指向结尾空节点,此时退出循环,返回空。
|
|
||||||
# 证明思路
|
|
||||||
设链表A不相交部分长度为a,链表B不相交部分长度为b,两个链表相交部分长度为c。<br>
|
|
||||||
在pa指向链表A时,即pa为空之前,pa经过链表A不相交部分和相交部分,走过的长度为a+c;<br>
|
|
||||||
pa指向链表B后,在移动相交节点之前经过链表B不相交部分,走过的长度为b,总合为a+c+b。<br>
|
|
||||||
同理,pb走过长度的总合为b+c+a。二者相等,即pa与pb可同时到达相交起始节点。 <br>
|
|
||||||
该方法可避免计算具体链表长度。
|
|
||||||
```cpp
|
|
||||||
class Solution {
|
|
||||||
public:
|
|
||||||
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
|
|
||||||
//链表为空时,返回空指针
|
|
||||||
if(headA == nullptr || headB == nullptr) return nullptr;
|
|
||||||
ListNode* pa = headA;
|
|
||||||
ListNode* pb = headB;
|
|
||||||
//pa与pb在遍历过全部节点后,同时指向结尾空节点时退出循环
|
|
||||||
while(pa != nullptr || pb != nullptr){
|
|
||||||
//pa为空时,将pa指向headB
|
|
||||||
if(pa == nullptr){
|
|
||||||
pa = headB;
|
|
||||||
}
|
|
||||||
//pa为空时,将pb指向headA
|
|
||||||
if(pb == nullptr){
|
|
||||||
pb = headA;
|
|
||||||
}
|
|
||||||
//pa与pb相等时,返回相交起始节点
|
|
||||||
if(pa == pb){
|
|
||||||
return pa;
|
|
||||||
}
|
|
||||||
pa = pa->next;
|
|
||||||
pb = pb->next;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
Reference in New Issue
Block a user