leetcode354. 俄罗斯套娃信封问题(动态规划-java)

俄罗斯套娃信封问题

  • leetcode354. 俄罗斯套娃信封问题
    • 题目描述:
    • 解题思路
    • 代码演示
  • 动态规划专题

leetcode354. 俄罗斯套娃信封问题

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/russian-doll-envelopes

题目描述:

给你一个二维整数数组 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

提示:
1 <= envelopes.length <= 105
envelopes[i].length == 2
1 <= wi, hi <= 105

解题思路

合法嵌套,是大的套小的,因此这个题就是最长递增子序列的一个变种.当于在二维平面中找一个最长递增的子序列,其长度就是最多能嵌套的信封个数。
递增子序列的解题方法可以查看leetcode300. 最长递增子序列
如何在二维数组中,运用递增子序列的方式.我们就需要现堆这个二维数组处理一下了:
先对宽度 w 进行升序排序,如果遇到 w 相同的情况,则按照高度 h 降序排序;之后把所有的 h 作为一个数组,在这个数组上计算 LIS 的长度就是答案。
用图演示一下,就明白为何能这样做了:
leetcode354. 俄罗斯套娃信封问题(动态规划-java)_第1张图片
然后在 h 上寻找最长递增子序列,这个子序列就是最优的嵌套方案:
leetcode354. 俄罗斯套娃信封问题(动态规划-java)_第2张图片

代码演示

   public int maxEnvelopes(int[][] envelopes) {
        int N = envelopes.length;  
         Arrays.sort(envelopes, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0] == o2[0] ? o2[1] - o1[1] : o1[0] - o2[0];
            }
        });

        int[]heights = new int[N];  
        for(int i = 0; i < N; i++){
            heights[i] = envelopes[i][1];    
        }
        return lengthOfLIS(heights);
    }
		
   	/**
   	* 最长递增子序列 可以直接复制进力扣测试
   	*/
    int lengthOfLIS(int[] nums) {
       int N = nums.length;
       //动态规划表
       int[]dp = new int[N];
       for(int i = 0; i < N; i++){
       	//base case 每个位置本身长度
           dp[i] = 1;
           for(int j = 0;j < i; j++){
            // i 位置依次向前比 ,比j 位置大,就是 1 + dp[i]
           // 根据不同j位置上的数,来更新最大值
               if(nums[i] > nums[j]){
                  dp[i] = Math.max(dp[i],1 + dp[j]);  
               }
               
           }
       }
       int res = 0;
         //取出 dp表中的最大值 就是我们要的答案.
       for (int i = 0; i < dp.length;i++){
           res = Math.max(res,dp[i]);
       }
       return res;
    }

上面的lengthOfLIS 这个方法时间复杂度是O(N2) n平方的,时间限制上可能过不去,可以进行下面的二分法改造>

 int lengthOfLIS(int[] nums) {
         int N = nums.length;
         int[]ends = new int[N];
         int count = 0;
         for(int i = 0; i < N ; i++){
            int cur = nums[i];
            int L = 0;
            int R = count;
            while(L < R){
                int mid = (L + R) / 2;
                if(ends[mid] >= cur){
                    R = mid;
                }else{
                    L = mid + 1;
                }
            }
            //
            if(L == count){
                count++;
            }
            ends[L] = cur;
         }
         return count;
     }

动态规划专题

leetcode300. 最长递增子序列

leetcode300. 最长递增子序列

leetcode213. 打家劫舍 II

leetcode337. 打家劫舍 III

leetcode198. 打家劫舍

leetcode174. 地下城游戏

打败怪兽的概率

leetcode688. 骑士在棋盘上的概率

你可能感兴趣的:(数据结构,java,算法,动态规划,java,leetcode,算法,数据结构)