Skip to content

Commit b77d7bd

Browse files
committed
feat: add solutions to lc problem: No.0300
No.0300.Longest Increasing Subsequence
1 parent 1bbc10e commit b77d7bd

File tree

3 files changed

+306
-9
lines changed

3 files changed

+306
-9
lines changed

solution/0300-0399/0300.Longest Increasing Subsequence/README.md

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,26 @@
6262

6363
时间复杂度 O(n²)。
6464

65-
**方法二:树状数组**
65+
**方法二:贪心 + 二分查找**
66+
67+
维护一个数组 `d[i]`,表示长度为 i 的最长上升子序列末尾元素的最小值,初始值 `d[1]=nums[0]`
68+
69+
直观上,`d[i]` 是单调递增数组。
70+
71+
证明:假设存在 `d[j] ≥ d[i]`,且 `j < i`,我们考虑从长度为 i 的最长上升子序列的末尾删除 `i - j` 个元素,那么这个序列长度变为 j,且第 j 个元素 `d[j]` 必然小于 `d[i]`,由于前面假设 `d[j] ≥ d[i]`,产生了矛盾,因此数组 d 是单调递增数组。
72+
73+
算法思路:
74+
75+
设当前求出的最长上升子序列的长度为 size,初始 `size=1`,从前往后遍历数组 nums,在遍历到 `nums[i]` 时:
76+
77+
-`nums[i] > d[size]`,则直接将 `nums[i]` 加入到数组 d 的末尾,并且更新 size 自增;
78+
- 否则,在数组 d 中二分查找(前面证明 d 是一个单调递增数组),找到第一个大于等于 nums[i] 的位置 idx,更新 `d[idx] = nums[i]`
79+
80+
最终返回 size。
81+
82+
时间复杂度 O(nlogn)。
83+
84+
**方法三:树状数组**
6685

6786
树状数组,也称作“二叉索引树”(Binary Indexed Tree)或 Fenwick 树。 它可以高效地实现如下两个操作:
6887

@@ -110,6 +129,24 @@ class Solution:
110129
return max(dp)
111130
```
112131

132+
贪心 + 二分查找:
133+
134+
```python
135+
class Solution:
136+
def lengthOfLIS(self, nums: List[int]) -> int:
137+
n = len(nums)
138+
d = [nums[0]]
139+
for x in nums[1:]:
140+
if x > d[-1]:
141+
d.append(x)
142+
else:
143+
idx = bisect_left(d, x)
144+
if idx == len(d):
145+
idx = 0
146+
d[idx] = x
147+
return len(d)
148+
```
149+
113150
树状数组:
114151

115152
```python
@@ -175,6 +212,37 @@ class Solution {
175212
}
176213
```
177214

215+
贪心 + 二分查找:
216+
217+
```java
218+
class Solution {
219+
public int lengthOfLIS(int[] nums) {
220+
int n = nums.length;
221+
int[] d = new int[n + 1];
222+
d[1] = nums[0];
223+
int size = 1;
224+
for (int i = 1; i < n; ++i) {
225+
if (nums[i] > d[size]) {
226+
d[++size] = nums[i];
227+
} else {
228+
int left = 1, right = size;
229+
while (left < right) {
230+
int mid = (left + right) >> 1;
231+
if (d[mid] >= nums[i]) {
232+
right = mid;
233+
} else {
234+
left = mid + 1;
235+
}
236+
}
237+
int p = d[left] >= nums[i] ? left : 1;
238+
d[p] = nums[i];
239+
}
240+
}
241+
return size;
242+
}
243+
}
244+
```
245+
178246
树状数组:
179247

180248
```java
@@ -251,6 +319,35 @@ function lengthOfLIS(nums: number[]): number {
251319
}
252320
```
253321

322+
贪心 + 二分查找:
323+
324+
```ts
325+
function lengthOfLIS(nums: number[]): number {
326+
const n = nums.length;
327+
let d = new Array(n + 1);
328+
d[1] = nums[0];
329+
let size = 1;
330+
for (let i = 1; i < n; ++i) {
331+
if (nums[i] > d[size]) {
332+
d[++size] = nums[i];
333+
} else {
334+
let left = 1, right = size;
335+
while (left < right) {
336+
const mid = (left + right) >> 1;
337+
if (d[mid] >= nums[i]) {
338+
right = mid;
339+
} else {
340+
left = mid + 1;
341+
}
342+
}
343+
const p = d[left] >= nums[i] ? left : 1;
344+
d[p] = nums[i];
345+
}
346+
}
347+
return size;
348+
};
349+
```
350+
254351
### **C++**
255352

256353
动态规划:
@@ -273,6 +370,29 @@ public:
273370
};
274371
```
275372
373+
贪心 + 二分查找:
374+
375+
```cpp
376+
class Solution {
377+
public:
378+
int lengthOfLIS(vector<int>& nums) {
379+
int n = nums.size();
380+
vector<int> d{nums[0]};
381+
for (int i = 1; i < n; ++i)
382+
{
383+
if (nums[i] > d[d.size() - 1]) d.push_back(nums[i]);
384+
else
385+
{
386+
int idx = lower_bound(d.begin(), d.end(), nums[i]) - d.begin();
387+
if (idx == d.size()) idx = 0;
388+
d[idx] = nums[i];
389+
}
390+
}
391+
return d.size();
392+
}
393+
};
394+
```
395+
276396
树状数组:
277397

278398
```cpp
@@ -357,6 +477,38 @@ func max(a, b int) int {
357477
}
358478
```
359479

480+
贪心 + 二分查找:
481+
482+
```go
483+
func lengthOfLIS(nums []int) int {
484+
n := len(nums)
485+
d := make([]int, n+1)
486+
d[1] = nums[0]
487+
size := 1
488+
for _, x := range nums[1:] {
489+
if x > d[size] {
490+
size++
491+
d[size] = x
492+
} else {
493+
left, right := 1, size
494+
for left < right {
495+
mid := (left + right) >> 1
496+
if d[mid] >= x {
497+
right = mid
498+
} else {
499+
left = mid + 1
500+
}
501+
}
502+
if d[left] < x {
503+
left = 1
504+
}
505+
d[left] = x
506+
}
507+
}
508+
return size
509+
}
510+
```
511+
360512
树状数组:
361513

362514
```go

solution/0300-0399/0300.Longest Increasing Subsequence/README_EN.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,24 @@ class Solution:
6464
return max(dp)
6565
```
6666

67+
Greedy & Binary search:
68+
69+
```python
70+
class Solution:
71+
def lengthOfLIS(self, nums: List[int]) -> int:
72+
n = len(nums)
73+
d = [nums[0]]
74+
for x in nums[1:]:
75+
if x > d[-1]:
76+
d.append(x)
77+
else:
78+
idx = bisect_left(d, x)
79+
if idx == len(d):
80+
idx = 0
81+
d[idx] = x
82+
return len(d)
83+
```
84+
6785
Binary Indexed Tree:
6886

6987
```python
@@ -127,6 +145,37 @@ class Solution {
127145
}
128146
```
129147

148+
Greedy & Binary search:
149+
150+
```java
151+
class Solution {
152+
public int lengthOfLIS(int[] nums) {
153+
int n = nums.length;
154+
int[] d = new int[n + 1];
155+
d[1] = nums[0];
156+
int size = 1;
157+
for (int i = 1; i < n; ++i) {
158+
if (nums[i] > d[size]) {
159+
d[++size] = nums[i];
160+
} else {
161+
int left = 1, right = size;
162+
while (left < right) {
163+
int mid = (left + right) >> 1;
164+
if (d[mid] >= nums[i]) {
165+
right = mid;
166+
} else {
167+
left = mid + 1;
168+
}
169+
}
170+
int p = d[left] >= nums[i] ? left : 1;
171+
d[p] = nums[i];
172+
}
173+
}
174+
return size;
175+
}
176+
}
177+
```
178+
130179
Binary Indexed Tree:
131180

132181
```java
@@ -203,6 +252,35 @@ function lengthOfLIS(nums: number[]): number {
203252
}
204253
```
205254

255+
Greedy & Binary search:
256+
257+
```ts
258+
function lengthOfLIS(nums: number[]): number {
259+
const n = nums.length;
260+
let d = new Array(n + 1);
261+
d[1] = nums[0];
262+
let size = 1;
263+
for (let i = 1; i < n; ++i) {
264+
if (nums[i] > d[size]) {
265+
d[++size] = nums[i];
266+
} else {
267+
let left = 1, right = size;
268+
while (left < right) {
269+
const mid = (left + right) >> 1;
270+
if (d[mid] >= nums[i]) {
271+
right = mid;
272+
} else {
273+
left = mid + 1;
274+
}
275+
}
276+
const p = d[left] >= nums[i] ? left : 1;
277+
d[p] = nums[i];
278+
}
279+
}
280+
return size;
281+
};
282+
```
283+
206284
### **C++**
207285

208286
Dynamic programming:
@@ -225,6 +303,29 @@ public:
225303
};
226304
```
227305
306+
Greedy & Binary search:
307+
308+
```cpp
309+
class Solution {
310+
public:
311+
int lengthOfLIS(vector<int>& nums) {
312+
int n = nums.size();
313+
vector<int> d{nums[0]};
314+
for (int i = 1; i < n; ++i)
315+
{
316+
if (nums[i] > d[d.size() - 1]) d.push_back(nums[i]);
317+
else
318+
{
319+
int idx = lower_bound(d.begin(), d.end(), nums[i]) - d.begin();
320+
if (idx == d.size()) idx = 0;
321+
d[idx] = nums[i];
322+
}
323+
}
324+
return d.size();
325+
}
326+
};
327+
```
328+
228329
Binary Indexed Tree:
229330

230331
```cpp
@@ -309,6 +410,38 @@ func max(a, b int) int {
309410
}
310411
```
311412

413+
Greedy & Binary search:
414+
415+
```go
416+
func lengthOfLIS(nums []int) int {
417+
n := len(nums)
418+
d := make([]int, n+1)
419+
d[1] = nums[0]
420+
size := 1
421+
for _, x := range nums[1:] {
422+
if x > d[size] {
423+
size++
424+
d[size] = x
425+
} else {
426+
left, right := 1, size
427+
for left < right {
428+
mid := (left + right) >> 1
429+
if d[mid] >= x {
430+
right = mid
431+
} else {
432+
left = mid + 1
433+
}
434+
}
435+
if d[left] < x {
436+
left = 1
437+
}
438+
d[left] = x
439+
}
440+
}
441+
return size
442+
}
443+
```
444+
312445
Binary Indexed Tree:
313446

314447
```go
Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
function lengthOfLIS(nums: number[]): number {
2-
let n = nums.length;
3-
let dp = new Array(n).fill(1);
4-
for (let i = 0; i < n; i++) {
5-
for (let j = 0; j < i; j++) {
6-
if (nums[j] < nums[i]) {
7-
dp[i] = Math.max(dp[i], dp[j] + 1);
2+
const n = nums.length;
3+
let d = new Array(n + 1);
4+
d[1] = nums[0];
5+
let size = 1;
6+
for (let i = 1; i < n; ++i) {
7+
if (nums[i] > d[size]) {
8+
d[++size] = nums[i];
9+
} else {
10+
let left = 1, right = size;
11+
while (left < right) {
12+
const mid = (left + right) >> 1;
13+
if (d[mid] >= nums[i]) {
14+
right = mid;
15+
} else {
16+
left = mid + 1;
17+
}
818
}
19+
const p = d[left] >= nums[i] ? left : 1;
20+
d[p] = nums[i];
921
}
1022
}
11-
return Math.max(...dp);
12-
}
23+
return size;
24+
};

0 commit comments

Comments
 (0)