法1:DP,LIS问题
O(N*N)基本方法,必须掌握!!!python的dp做法会超时,但保底方法必须掌握!!!
Python
class Solution:
def maxEnvelopes(self, envelopes: List[List[int]]) -> int:
# envelopes.sort(key=lambda x: x[0]) # 只按照0维度升序排列
envelopes.sort(key=lambda x: (x[0], -x[1])) # 首先对信封进行排序:按宽度升序,宽度相同则按高度降序
h_list = [item[1] for item in envelopes]
n = len(h_list)
dp = [1] * n # dp[i]以h_list[i]元素结尾的最长递增子序列长度
for i in range(n):
for j in range(i):
if h_list[j] < h_list[i]:
dp[i] = max(dp[j] + 1, dp[i])
return max(dp)
Java
class Solution {
public int maxEnvelopes(int[][] envelopes) {
int n = envelopes.length;
if (n < 2) {
return n;
}
Arrays.sort(envelopes, (a1, a2) -> {
return a1[0] == a2[0] ? a2[1] - a1[1] : a1[0] - a2[0];
});
List<Integer> list = new ArrayList<>();
for (int i = 0; i < n; ++i) {
list.add(envelopes[i][1]);
}
int[] dp = new int[n];
int max = 1;
Arrays.fill(dp, 1);
for (int i = 1; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (list.get(i) > list.get(j) && (dp[j] + 1 > dp[i])) {
dp[i] = dp[j] + 1;
}
}
max = Math.max(max, dp[i]);
}
return max;
}
}
法2:耐心排序(二分法)
O(nlgn)
详细讲解参考灵神视频!
Python
class Solution:
def maxEnvelopes(self, envelopes: List[List[int]]) -> int:
envelopes.sort(key=lambda x: (x[0], -x[1]))
h_liist = [item[1] for item in envelopes]
res, n = 1, len(h_liist)
dp = []
for x in h_liist:
j = bisect_left(dp, x) # 若 x 已存在于 dp 中,返回第一个等于 x 的元素的索引
# 若 x 不存在于 dp 中,返回第一个大于 x 的元素的索引
if j == len(dp):
dp.append(x)
else:
dp[j] = x
return len(dp)
Java
注意,此处二分的左右索引与习惯不太一致!
class Solution {
public int maxEnvelopes(int[][] envelopes) {
int n = envelopes.length;
if (n < 2) {
return n;
}
Arrays.sort(envelopes, (a1, a2) -> {
return a1[0] == a2[0] ? a2[1] - a1[1] : a1[0] - a2[0];
});
List<Integer> list = new ArrayList<>();
for (int i = 0; i < n; ++i) {
list.add(envelopes[i][1]);
}
int max = lis(list);
return max;
}
int lis(List<Integer> list) {
int n = list.size();
if (n < 2) {
return n;
}
int count = 0;
int[] top = new int[n];
for (int i = 0; i < n; ++i) {
int left = 0, right = count, curVal = list.get(i); // 注意: 这里right取得n
while (left < right) { // 注意: 这里没有"="
int mid = left + (right - left) / 2;
if (top[mid] >= curVal) {
right = mid;
} else {
left = mid + 1;
}
}
if (left == count) {
++count;
}
top[left] = curVal;
}
return count;
}
}