@@ -158,19 +158,15 @@ class Solution:
158
158
if n == 0 : return 0
159
159
dp = [1 ] * n
160
160
ans = 1
161
- intervals.sort(key = lambda a : a[1 ])
161
+ intervals.sort(key = lambda a : a[0 ])
162
162
163
163
for i in range (len (intervals)):
164
164
for j in range (i - 1 , - 1 , - 1 ):
165
165
if intervals[i][0 ] >= intervals[j][1 ]:
166
166
dp[i] = max (dp[i], dp[j] + 1 )
167
- # 由于我事先进行了排序,因此倒着找的时候,找到的第一个一定是最大的数,因此不用往前继续找了。
168
- # 这也是为什么我按照结束时间排序的原因。
169
- break
170
- dp[i] = max (dp[i], dp[i - 1 ])
171
- ans = max (ans, dp[i])
167
+ break # 由于是按照开始时间排序的, 因此可以剪枝
172
168
173
- return n - ans
169
+ return n - max (dp)
174
170
```
175
171
176
172
** 复杂度分析**
@@ -216,17 +212,20 @@ https://leetcode-cn.com/problems/maximum-length-of-pair-chain/
216
212
217
213
``` py
218
214
class Solution :
219
- def findLongestChain (self , pairs : List[List[int ]]) -> int :
220
- n = len (pairs)
215
+ def findLongestChain (self , intervals : List[List[int ]]) -> int :
216
+ n = len (intervals)
217
+ if n == 0 : return 0
221
218
dp = [1 ] * n
222
219
ans = 1
223
- pairs.sort(key = lambda a : a[0 ])
224
- for i in range (n):
225
- for j in range (i):
226
- if pairs[i][0 ] > pairs[j][1 ]:
220
+ intervals.sort(key = lambda a : a[0 ])
221
+
222
+ for i in range (len (intervals)):
223
+ for j in range (i - 1 , - 1 , - 1 ):
224
+ if intervals[i][0 ] > intervals[j][1 ]:
227
225
dp[i] = max (dp[i], dp[j] + 1 )
228
- ans = max (ans, dp[i])
229
- return ans
226
+ break # 由于是按照开始时间排序的, 因此可以剪枝
227
+
228
+ return max (dp)
230
229
```
231
230
232
231
** 复杂度分析**
@@ -272,19 +271,20 @@ Example:
272
271
273
272
``` py
274
273
class Solution :
275
- def findMinArrowShots (self , points : List[List[int ]]) -> int :
276
- n = len (points )
274
+ def findMinArrowShots (self , intervals : List[List[int ]]) -> int :
275
+ n = len (intervals )
277
276
if n == 0 : return 0
278
277
dp = [1 ] * n
279
- cnt = 1
280
- points .sort(key = lambda a :a[ 1 ])
278
+ ans = 1
279
+ intervals .sort(key = lambda a : a[ 0 ])
281
280
282
- for i in range (n ):
283
- for j in range (0 , i ):
284
- if points [i][0 ] > points [j][1 ]:
281
+ for i in range (len (intervals) ):
282
+ for j in range (i - 1 , - 1 , - 1 ):
283
+ if intervals [i][0 ] > intervals [j][1 ]:
285
284
dp[i] = max (dp[i], dp[j] + 1 )
286
- cnt = max (cnt, dp[i])
287
- return cnt
285
+ break # 由于是按照开始时间排序的, 因此可以剪枝
286
+
287
+ return max (dp)
288
288
```
289
289
290
290
** 复杂度分析**
@@ -313,6 +313,42 @@ class Solution:
313
313
return len (d)
314
314
```
315
315
316
+ 如果求最长不递减子序列呢?
317
+
318
+ 我们只需要将最左插入改为最右插入即可。代码:
319
+
320
+ ``` py
321
+ class Solution :
322
+ def lengthOfLIS (self , A : List[int ]) -> int :
323
+ d = []
324
+ for a in A:
325
+ # 这里改为最右
326
+ i = bisect.bisect(d, a)
327
+ if i < len (d):
328
+ d[i] = a
329
+ # 这里改为小于等号
330
+ elif not d or d[- 1 ] <= a:
331
+ d.append(a)
332
+ return len (d)
333
+ ```
334
+
335
+ 最左插入和最右插入分不清的可以看看我的二分专题。
336
+
337
+ 也可以这么写,更简单一点:
338
+
339
+ ``` py
340
+ def LIS (A ):
341
+ d = []
342
+ for a in A:
343
+ # 如果求要严格递增就改为最左插入 bisect_left 即可
344
+ i = bisect.bisect(d, a)
345
+ if i == len (d):
346
+ d.append(a)
347
+ elif d[i] != a:
348
+ d[i] = a
349
+ return len (d)
350
+ ```
351
+
316
352
## More
317
353
318
354
其他的我就不一一说了。
@@ -408,6 +444,52 @@ class Solution:
408
444
return len (target) - LIS(B)
409
445
```
410
446
447
+ - [ 1626. 无矛盾的最佳球队] ( https://leetcode-cn.com/problems/best-team-with-no-conflicts/ )
448
+
449
+ 不就是先排下序,然后求 scores 的最长上升子序列么?
450
+
451
+ 参考代码:
452
+
453
+ ``` py
454
+ class Solution :
455
+ def bestTeamScore (self , scores : List[int ], ages : List[int ]) -> int :
456
+ n = len (scores)
457
+ persons = list (zip (ages, scores))
458
+ persons.sort(key = lambda x : (x[0 ], x[1 ]))
459
+ dp = [persons[i][1 ] for i in range (n)]
460
+ for i in range (n):
461
+ for j in range (i):
462
+ if persons[i][1 ] >= persons[j][1 ]:
463
+ dp[i] = max (dp[i], dp[j]+ persons[i][1 ])
464
+ return max (dp)
465
+ ```
466
+
467
+ 再比如 [ 这道题] ( https://binarysearch.com/problems/Circular-Longest-Increasing-Subsequence ) 无非就是加了一个条件,我们可以结合循环移位的技巧来做。
468
+
469
+ > 关于循环移位算法西法在之前的文章 [ 文科生都能看懂的循环移位算法] ( https://lucifer.ren/blog/2020/02/20/rotate-list/ ) 也做了详细讲解,不再赘述。
470
+
471
+ 参考代码:
472
+
473
+ ``` py
474
+ class Solution :
475
+ def solve (self , nums ):
476
+ n = len (nums)
477
+ ans = 1
478
+ def LIS (A ):
479
+ d = []
480
+ for a in A:
481
+ i = bisect.bisect_left(d,a)
482
+ if i == len (d): d.append(a)
483
+ else : d[i] = a
484
+ return len (d)
485
+ nums += nums
486
+ for i in range (n):
487
+ ans = max (ans , LIS(nums[i:i+ n]))
488
+ return ans
489
+ ```
490
+
491
+ 大家把我讲的思路搞懂,这几个题一写,还怕碰到类似的题不会么?** 只有熟练掌握基础的数据结构与算法,才能对复杂问题迎刃有余。** 最长上升子序列就是一个非常经典的基础算法,把它彻底搞懂,再去面对出题人的各种换皮就不怕了。相反,如果你不去思考题目背后的逻辑,就会刷地很痛苦。题目稍微一变化你就不会了,这也是为什么很多人说** 刷了很多题,但是碰到新的题目还是不会做** 的原因之一。关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。
492
+
411
493
更多题解可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 38K star 啦。
412
494
413
495
![ ] ( https://tva1.sinaimg.cn/large/007S8ZIlly1gfcuzagjalj30p00dwabs.jpg )
0 commit comments