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(1)$,我没有算result数组(返回值所需容器占的空间)
|
||||
* 时间复杂度:O(nlog n) ,有一个快排
|
||||
* 空间复杂度:O(n),有一个快排,最差情况(倒序)时,需要n次递归调用。因此确实需要O(n)的栈空间
|
||||
|
||||
|
||||
## 总结
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
也可以直接看我的B站视频:[带你学透回溯算法-组合问题(对应力扣题目:77.组合)](https://www.bilibili.com/video/BV1ti4y1L7cv#reply3733925949)
|
||||
|
||||
# 思路
|
||||
## 思路
|
||||
|
||||
|
||||
本题这是回溯法的经典题目。
|
||||
@ -232,7 +232,7 @@ void backtracking(参数) {
|
||||
|
||||
**对比一下本题的代码,是不是发现有点像!** 所以有了这个模板,就有解题的大体方向,不至于毫无头绪。
|
||||
|
||||
# 总结
|
||||
## 总结
|
||||
|
||||
组合问题是回溯法解决的经典问题,我们开始的时候给大家列举一个很形象的例子,就是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
|
||||
class Solution {
|
||||
List<List<Integer>> result = new ArrayList<>();
|
||||
@ -366,6 +366,8 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
### Python
|
||||
|
||||
Python2:
|
||||
```python
|
||||
class Solution(object):
|
||||
@ -395,7 +397,6 @@ class Solution(object):
|
||||
return result
|
||||
```
|
||||
|
||||
## Python
|
||||
```python
|
||||
class Solution:
|
||||
def combine(self, n: int, k: int) -> List[List[int]]:
|
||||
@ -432,7 +433,7 @@ class Solution:
|
||||
```
|
||||
|
||||
|
||||
## javascript
|
||||
### javascript
|
||||
|
||||
剪枝:
|
||||
```javascript
|
||||
@ -456,7 +457,7 @@ const combineHelper = (n, k, startIndex) => {
|
||||
}
|
||||
```
|
||||
|
||||
## TypeScript
|
||||
### TypeScript
|
||||
|
||||
```typescript
|
||||
function combine(n: number, k: number): number[][] {
|
||||
@ -479,7 +480,7 @@ function combine(n: number, k: number): number[][] {
|
||||
|
||||
|
||||
|
||||
## Go
|
||||
### Go
|
||||
```Go
|
||||
var res [][]int
|
||||
func combine(n int, k int) [][]int {
|
||||
@ -534,7 +535,7 @@ func backtrack(n,k,start int,track []int){
|
||||
}
|
||||
```
|
||||
|
||||
## C
|
||||
### C
|
||||
```c
|
||||
int* path;
|
||||
int pathTop;
|
||||
@ -642,7 +643,7 @@ int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
|
||||
}
|
||||
```
|
||||
|
||||
## Swift
|
||||
### Swift
|
||||
|
||||
```swift
|
||||
func combine(_ n: Int, _ k: Int) -> [[Int]] {
|
||||
|
@ -238,7 +238,7 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
# 总结
|
||||
## 总结
|
||||
|
||||
这次我们又深度剖析了一道二叉树的“简单题”,大家会发现,真正的把题目搞清楚其实并不简单,leetcode上accept了和真正掌握了还是有距离的。
|
||||
|
||||
@ -248,7 +248,7 @@ public:
|
||||
|
||||
如果已经做过这道题目的同学,读完文章可以再去看看这道题目,思考一下,会有不一样的发现!
|
||||
|
||||
# 相关题目推荐
|
||||
## 相关题目推荐
|
||||
|
||||
这两道题目基本和本题是一样的,只要稍加修改就可以AC。
|
||||
|
||||
|
@ -93,7 +93,7 @@ public:
|
||||
};
|
||||
```
|
||||
* 时间复杂度:O(nlog n) ,有一个快排
|
||||
* 空间复杂度:O(1)
|
||||
* 空间复杂度:O(n),有一个快排,最差情况(倒序)时,需要n次递归调用。因此确实需要O(n)的栈空间
|
||||
|
||||
大家此时会发现如此复杂的一个问题,代码实现却这么简单!
|
||||
|
||||
|
@ -105,8 +105,8 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
* 时间复杂度:$O(n\log n)$,因为有一个快排
|
||||
* 空间复杂度:$O(1)$
|
||||
* 时间复杂度:O(nlog n),因为有一个快排
|
||||
* 空间复杂度:O(1),有一个快排,最差情况(倒序)时,需要n次递归调用。因此确实需要O(n)的栈空间
|
||||
|
||||
可以看出代码并不复杂。
|
||||
|
||||
|
@ -315,6 +315,30 @@ function 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