【动态规划】—— 354. 俄罗斯套娃信封问题(二维递增子序列)
题目描述
给你一个二维整数数组 envelopes ,其中 envelopes[i] = [wi, hi] ,表示第 i 个信封的宽度和高度。
当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。
请计算 最多能有多少个 信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
注意:不允许旋转信封。
示例 1:
输入:envelopes = [[5,4],[6,4],[6,7],[2,3]]
输出:3
解释:最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。
示例 2:
输入:envelopes = [[1,1],[1,1],[1,1]]
输出:1
解题思路
先对宽度 w 进行升序排序, 如果遇到 w 相同的情况, 则按照高度 h 降
序排序。 之后把所有的 h 作为⼀个数组, 在这个数组上计算 LIS 的长度就
是答案。
这个解法的关键在于, 对于宽度 w 相同的数对, 要对其高度 h 进行降序
排序。 因为两个宽度相同的信封不能相互包含的, 逆序排序保证在 w 相同
的数对中最多只选取一个。
import java.util.Arrays;
//leetcode submit region begin(Prohibit modification and deletion)
class Solution_300 {
/**
* 动态规划
* @param nums
* @return
*/
public int lengthOfLIS_1(int[] nums) {
int[] dp = new int[nums.length];
//base case :dp数组全都初始化为1
Arrays.fill(dp,1);
for(int i=0;i<nums.length;i++){
for(int j = 0;j <i;j++){
if(nums[i]>nums[j]){
dp[i] = Math.max(dp[i],dp[j]+1);
}
}
}
int res = 0;
//重新遍历一遍数组,找到最长的递增子序列长度
for(int i = 0;i < dp.length;i++){
res = Math.max(res,dp[i]);
}
return res;
}
public int lengthOfLIS(int[] nums) {
int[] top = new int[nums.length];
//排堆数初始化为0
int piles = 0;
for (int i = 0; i < nums.length; i++) {
//要处理的扑克牌
int poker = nums[i];
/**
* 搜索左侧边界的二分搜索
*/
int left = 0,right = piles;
while (left < right){
int mid = (left + right) /2;
if (top[mid] > poker){
right = mid;
}else if (top[mid] < poker){
left = mid + 1;
}else {
right = mid;
}
}
//没有找到合适的排堆,新建一堆
if (left == piles) piles++;
top[left] = poker;
}
//排堆数就是LIS长度
return piles;
}
}
//leetcode submit region end(Prohibit modification and deletion)