Skip to content

Commit b6d4c8d

Browse files
committed
update 209
1 parent eb2916f commit b6d4c8d

File tree

6 files changed

+144
-29
lines changed

6 files changed

+144
-29
lines changed

src/leetcode/problem/0001.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ time complexity?
4747

4848
## 解题思路
4949

50-
这道题最优的做法时间复杂度是 O(n)。
50+
这道题最优的做法时间复杂度是 `O(n)`
5151

52-
使用哈希表,顺序扫描数组,对每一个元素,在 object 中找能组合给定值的另一半数字,如果找到了,直接返回 2 个数字的下标即可。如果找不到,就把这个数字存入 object 中,等待扫到“另一半”数字的时候,再取出来返回结果。
52+
使用哈希表,顺序扫描数组,对每一个元素,在 `object` 中找能组合给定值的另一半数字,如果找到了,直接返回 2 个数字的下标即可。如果找不到,就把这个数字存入 `object` 中,等待扫到“另一半”数字的时候,再取出来返回结果。
5353

5454
## 代码
5555

src/leetcode/problem/0005.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,13 @@ Given a string `s`, return _the longest_ _palindromic_ _substring_ in `s`.
5454
- 定义动态规划数组 `dp`,其中 `dp[i][j]` 表示字符串 `s` 从索引 `i` 到索引 `j` 是否为回文串。
5555
- 状态转移方程为:
5656

57-
- `s[i] = s[j] && dp[i+1][j-1] = true` 时,`dp[i][j] = true`
57+
- `s[i] == s[j] && dp[i+1][j-1] == true` 时,`dp[i][j] = true`
5858
- 否则,`dp[i][j] = false`
5959

6060
- 边界条件:
6161

6262
- `dp[i][i] = true`
63-
- `s[i] = s[i+1]` 时,`dp[i][i+1] = true`
63+
- `s[i] == s[i+1]` 时,`dp[i][i+1] = true`
6464

6565
- 时间复杂度:`O(n^2)`,其中 `n` 是字符串的长度。
6666
- 空间复杂度:`O(n^2)`

src/leetcode/problem/0014.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ If there is no common prefix, return an empty string `""`.
3737

3838
## 解题思路
3939

40-
### 解法一:循环比较
40+
### 思路一:循环比较
4141

4242
初始化公共前缀为字符串数组中的第一个字符串,然后将数组中的字符串与公共前缀一依次比较,每次比较出不同时就缩小公共前缀,直到公共前缀为空或者遍历完所有字符串数组。
4343

4444
- 时间复杂度:`O(len(strs[0]))``O(len(strs))`
4545
- 空间复杂度:`O(len(strs[0]))`
4646

47-
### 解法二:二维数组
47+
### 思路二:二维数组
4848

4949
把字符串列表看成一个二维数组,然后用一个嵌套 `for` 循环计算这个二维数组前面有多少列的元素完全相同即可。
5050

src/leetcode/problem/0151.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ solve it **in-place** with `O(1)` extra space?
6060

6161
## 解题思路
6262

63-
### 解法一:分割+倒序
63+
### 思路一:分割+倒序
6464

6565
常规的方式是把 `s` 按空格 `split` 成若干单词,然后 `reverse` 这些单词的顺序,最后把这些单词 `join` 成句子。
6666

@@ -71,7 +71,7 @@ solve it **in-place** with `O(1)` extra space?
7171
- `join()` 方法为 `O(n)`
7272
- 空间复杂度: `O(n)`,新建的字符串数组总长度 `≤n` ,占用 `O(n)` 大小的额外空间。
7373

74-
### 解法二:双指针
74+
### 思路二:双指针
7575

7676
- 倒序遍历字符串 `s` ,记录单词左右索引边界 `i` , `j`
7777
- 每确定一个单词的边界,则将其添加至单词列表 `res`

src/leetcode/problem/0167.md

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,24 @@ Your solution must use only constant extra space.
4848

4949
## 题目大意
5050

51-
找出两个数之和等于 target 的两个数字,要求输出它们的下标。注意一个数字不能使用 2 次。下标从小到大输出。假定题目一定有一个解。
51+
给你一个下标从 `1` 开始的整数数组 `numbers` ,该数组已按 **非递减顺序排列** ,请你从数组中找出满足相加之和等于目标数 `target` 的两个数。如果设这两个数分别是 `numbers[index1]``numbers[index2]` ,则 `1 <= index1 < index2 <= numbers.length`
52+
53+
以长度为 `2` 的整数数组 `[index1, index2]` 的形式返回这两个整数的下标 `index1``index2`
54+
55+
你可以假设每个输入 **只对应唯一的答案** ,而且你 **不可以** 重复使用相同的元素。
56+
57+
你所设计的解决方案必须只使用常量级的额外空间。
5258

5359
## 解题思路
5460

5561
这一题比 [第 1 题 Two Sum](./0001.md) 的问题还要简单,因为这里数组是有序的。可以直接用第一题的解法解决这道题。
5662

5763
## 代码
5864

65+
:::: code-tabs
66+
67+
@tab 对撞指针
68+
5969
```javascript
6070
// 解法一 这一题可以利用数组有序的特性,使用对撞指针
6171
/**
@@ -64,37 +74,43 @@ Your solution must use only constant extra space.
6474
* @return {number[]}
6575
*/
6676
var twoSum = function (numbers, target) {
67-
let i = 0;
68-
let j = numbers.length - 1;
69-
while (i < j) {
70-
if (numbers[i] + numbers[j] === target) {
71-
return [i + 1, j + 1];
72-
} else if (numbers[i] + numbers[j] < target) {
73-
i++;
74-
} else {
75-
j--;
76-
}
77-
}
77+
let i = 0;
78+
let j = numbers.length - 1;
79+
while (i < j) {
80+
if (numbers[i] + numbers[j] === target) {
81+
return [i + 1, j + 1];
82+
} else if (numbers[i] + numbers[j] < target) {
83+
i++;
84+
} else {
85+
j--;
86+
}
87+
}
7888
};
89+
```
90+
91+
@tab 哈希表
7992

93+
```javascript
8094
// 解法二 不管数组是否有序,空间复杂度比上一种解法要多 O(n)
8195
/**
8296
* @param {number[]} nums
8397
* @param {number} target
8498
* @return {number[]}
8599
*/
86100
var twoSum = function (nums, target) {
87-
let obj = {};
88-
for (let i = 0; i < nums.length; i++) {
89-
let another = target - nums[i];
90-
if (another in obj) {
91-
return [obj[another], i];
92-
}
93-
obj[nums[i]] = i;
94-
}
101+
let obj = {};
102+
for (let i = 0; i < nums.length; i++) {
103+
let another = target - nums[i];
104+
if (another in obj) {
105+
return [obj[another], i];
106+
}
107+
obj[nums[i]] = i;
108+
}
95109
};
96110
```
97111

112+
::::
113+
98114
## 相关题目
99115

100116
:::: md-demo 相关题目

src/leetcode/problem/0209.md

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,48 @@ solution of which the time complexity is `O(n log(n))`.
4343

4444
找出该数组中满足其总和大于等于 `target` 的长度最小的 **子数组** ,并返回其长度。如果不存在符合条件的子数组,返回 `0`
4545

46+
子数组是数组中连续的非空元素序列。
47+
4648
## 解题思路
4749

50+
### 思路一:滑动窗口
51+
4852
1. 初始化变量:使用两个指针(或滑动窗口)来遍历数组;
4953
2. 扩大窗口:移动右指针,向右扩大求和;
5054
3. 缩小窗口:一旦窗口总和大于等于 `target`,就移动左指针缩小窗口;
5155
4. 更新最小长度:过程中更新最小长度;
5256

53-
时间复杂度:`O(n)`,空间复杂度:`O(1)`
57+
- 时间复杂度:`O(n)`,其中 n 是数组的长度;
58+
- 空间复杂度:`O(1)`
59+
60+
### 思路二:暴力查找
61+
62+
1. 初始化子数组的最小长度为无穷大;
63+
2. 枚举数组 `nums` 中的每个下标作为子数组的开始下标;
64+
3. 对于每个开始下标 `i`,需要找到大于或等于 `i` 的最小下标 `j`,使得从 `nums[i]``nums[j]` 的元素和大于或等于 `s`
65+
4. 更新子数组的最小长度(此时子数组的长度是 `j−i+1`);
66+
67+
- 时间复杂度:`O(n^2)`,需要遍历每个下标作为子数组的开始下标,对于每个开始下标,需要遍历其后面的下标;
68+
- 空间复杂度:`O(1)`
69+
70+
### 思路三:二分查找
71+
72+
1. 暴力查找的时间复杂度是 `O(n^2)`,因为在确定每个子数组的开始下标后,找到长度最小的子数组需要 `O(n)` 的时间。如果使用二分查找,则可以将时间优化到 `O(logn)`
73+
2. 为了使用二分查找,需要额外创建一个数组 sums 用于存储数组 nums 的前缀和,其中 `sums[i]` 表示从 `nums[0]``nums[i−1]` 的元素和。
74+
3. 得到前缀和之后,对于每个开始下标 `i`,可通过二分查找得到大于或等于 `i` 的最小下标 `bound`,使得 `sums[bound]−sums[i−1]≥s`,并更新子数组的最小长度(此时子数组的长度是 `bound−(i−1)`)。
75+
76+
因为这道题保证了数组中每个元素都为正,所以前缀和一定是递增的,这一点保证了二分的正确性。如果题目没有说明数组中每个元素都为正,这里就不能使用二分来查找这个位置了。
77+
78+
- 时间复杂度:`O(nlogn)`,遍历每个下标的时间复杂度是 `O(n)`,二分查找的时间复杂度是 `O(logn)`,因此总时间复杂度是 `O(nlogn)`
79+
80+
- 空间复杂度:`O(n)`,额外创建数组 `sums` 存储前缀和。
5481

5582
## 代码
5683

84+
:::: code-tabs
85+
86+
@tab 滑动窗口
87+
5788
```javascript
5889
/**
5990
* @param {number} target
@@ -76,6 +107,74 @@ var minSubArrayLen = function (target, nums) {
76107
};
77108
```
78109

110+
@tab 暴力查找
111+
112+
```javascript
113+
/**
114+
* @param {number} target
115+
* @param {number[]} nums
116+
* @return {number}
117+
*/
118+
var minSubArrayLen = function (target, nums) {
119+
let n = nums.length,
120+
res = Infinity;
121+
if (n == 0) return 0;
122+
123+
for (let i = 0; i < n; i++) {
124+
let sum = 0;
125+
for (let j = i; j < n; j++) {
126+
sum += nums[j];
127+
if (sum >= target) {
128+
res = Math.min(res, j - i + 1);
129+
break;
130+
}
131+
}
132+
}
133+
return res == Infinity ? 0 : res;
134+
};
135+
```
136+
137+
@tab 二分查找
138+
139+
```javascript
140+
/**
141+
* @param {number} target
142+
* @param {number[]} nums
143+
* @return {number}
144+
*/
145+
var minSubArrayLen = function (target, nums) {
146+
let n = nums.length,
147+
sum = [0],
148+
res = Infinity;
149+
for (let i = 1; i <= n; i++) {
150+
sum[i] = nums[i - 1] + sum[i - 1];
151+
}
152+
for (let i = 1; i <= n; i++) {
153+
let newTarget = target + sum[i - 1];
154+
let bound = binarySearch(sum, newTarget, i, n);
155+
if (bound != -1) {
156+
res = Math.min(res, bound - i + 1);
157+
}
158+
}
159+
return res == Infinity ? 0 : res;
160+
};
161+
162+
var binarySearch = function (arr, target, l, r) {
163+
if (arr[r] < target) return -1;
164+
while (l < r) {
165+
let mid = (l + r) >> 1;
166+
if (arr[mid] < target) {
167+
l = mid + 1;
168+
} else {
169+
r = mid;
170+
}
171+
}
172+
return arr[l] >= target ? l : -1;
173+
};
174+
```
175+
176+
::::
177+
79178
## 相关题目
80179

81180
:::: md-demo 相关题目

0 commit comments

Comments
 (0)