首先,假设你已经做过300. 最长上升子序列,并能推导二分查找法及其正确性。
信封宽高为(w, h),当你w从小到大排列时,你可能觉得,该问题变成了最长上升子序列,只要高度一直增高,并找到最长的套娃层数即可。
但是有一个例外,就是你找到的上升序列,尽管高度递增,但可能会出现宽度相等的情况。
比如对于信封(1, 2) (1, 3),按照w排列,并找最长上升子序列后,得出答案是2。
为了避免这个情况,将信封宽度从小到大,同时高度从大到小排列。(比如(1,2)(1,3)(2,5)会排列成(1,3)(1,2)(2,5),这样能保证找到高度递增的子序列时,该子序列的宽度一定是不相等的。
我的答案:
class Solution:
def maxEnvelopes(self, envelopes) -> int:
envelopes.sort(key=lambda x: (x[0], -x[1])) # 按照宽度递增,高度递减排序
print(envelopes)
dp = []
# 接下来等同LIS
for i, en in enumerate(envelopes):
l, r = 0, len(dp) - 1
pivot = len(dp)
while l <= r:
mid = (l+r) // 2
if en[1] <= dp[mid]:
pivot = min(pivot, mid)
r = mid-1
else:
l = mid+1
if pivot == len(dp):
dp.append(en[1])
else:
dp[pivot] = en[1]
print(dp)
return len(dp)
顺便一提,官方题解中用了lower_bound的思路来做,比较简洁。
由于二分查找问题容易出错,我阅读了youtube上五点七边的视频,并改写如下。改写后清爽多了:
class Solution:
def maxEnvelopes(self, envelopes: List[List[int]]) -> int:
envelopes.sort(key=lambda x: (x[0], -x[1]))
dp = []
for i, en in enumerate(envelopes):
l, r = -1, len(dp)
while l != r-1:
m = (l+r) // 2
if en[1] <= dp[m]:
r = m
else:
l = m
if r == len(dp):
dp.append(en[1])
else:
dp[r] = en[1]
return len(dp)