俄罗斯套娃信封问题(LeetCode 354)

俄罗斯套娃信封问题(LeetCode 354)

给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。

请计算最多能有多少个信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。

说明:
不允许旋转信封。

示例:

输入: envelopes = [[5,4],[6,4],[6,7],[2,3]]
输出: 3 
解释: 最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。
  1. 暴力的动态规划方法(可能超时)

    public int maxEnvelopes(int[][] envelopes) {
        int[] temp;
        int res1 = 1;
        //按宽度从小到大排序,相同宽度时高度从小到大排序
        for(int i = 0;i<envelopes.length;i++){
            for(int j = i+1;j<envelopes.length;j++){
                if(envelopes[i][0]>envelopes[j][0] || (envelopes[i][0]==envelopes[j][0] && envelopes[i][1]>envelopes[j][1])){
                    temp = envelopes[i];
                    envelopes[i] = envelopes[j];
                    envelopes[j] = temp;
                }
            }
        }
        //对于每个信封,它能塞进的信封都只可能出现在它右侧
        //res记录以第i个信封为最后一个(套娃中最小的套娃),它的“俄罗斯套娃”信封个数。例如长宽最大的信封,res[i]=1
        //从右往左遍历,对于第i个信封,遍历其i+1至最后一个信封。
        //如果当前信封的长和宽都比第i个信封的大,那么更新res数组:
        //res[i] = Math.max(res[i],res[j]+1);
        int[] res = new int[envelopes.length];
        for(int i = envelopes.length-1;i>=0;i--){
            res[i] = 1;
            for (int j = i+1;j<envelopes.length;j++){
                if(envelopes[i][1] < envelopes[j][1] && envelopes[i][0] < envelopes[j][0]){
                    res[i] = Math.max(res[i],res[j]+1);
                }
            }
            resnum = Math.max(resnum,res[i]);
        }
        return resnum;
    }
    
  2. 转换为求最长递增子序列问题

    我们将宽度由小到大排序,同样宽度的信封要求高度由大到小。

    高度所组成的数组,求最长的上升子序列,其值就是信封的最大值。

    个人的一些理解:假设高度所组成的数组中有个高度h,如果它之前有一个比h还小的高度h0,就可以吧子序列长度+1(信封问题中就表示可以把h0塞到h信封中)。因为h的宽度一定比h0大,这已经事先排序完成了。

        public int maxEnvelopes(int[][] envelopes) {
            if(envelopes.length<=1)
                return envelopes.length;
            int[] temp;
            //排序:先排宽度,从小到大;对于相同的宽度,高度从大到小。
            for(int i = 0;i<envelopes.length;i++){
                for(int j = i+1;j<envelopes.length;j++){
                    if(envelopes[i][0]>envelopes[j][0] || (envelopes[i][0]==envelopes[j][0] && envelopes[i][1]<envelopes[j][1])){
                        temp = envelopes[i];
                        envelopes[i] = envelopes[j];
                        envelopes[j] = temp;
                    }
                }
            }
            //对于排序完之后的高度h,求最长上升子序列
            int res = 0;
            int[] dp = new int[envelopes.length];
            for(int i = 0;i<envelopes.length;i++){
                dp[i] = 1;
                for(int j = 0;j<i;j++){
                    if(envelopes[i][1] > envelopes[j][1]){
                        dp[i] = Math.max(dp[i],dp[j]+1);
                    }
                }
            }
            //返回dp中的最大值即可
            for(int i:dp){
                if(res<i) res=i;
            }
            return res;
        }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值