栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Leetcode 354题:俄罗斯套娃信封问题

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Leetcode 354题:俄罗斯套娃信封问题

1.题目描述

给你一个二维整数数组 envelopes ,其中 envelopes[i] = [wi, hi] ,表示第 i 个信封的宽度和高度。

当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。

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

注意:不允许旋转信封。

示例1

输入:envelopes = [[5,4],[6,4],[6,7],[2,3]]
输出:3
解释:最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。

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

2.思路分析

这道题的解法是⽐较巧妙的:

先对宽度 w 进⾏升序排序,如果遇到 w 相同的情况,则按照⾼度 h 降序排序。之后把所有的 h 作为⼀个数组,在这个数组上计算 LIS 的⻓度就是答案。

画个图理解⼀下,先对这些数对进⾏排序:

 

然后在 h 上寻找最⻓递增⼦序列: 

 

这个⼦序列就是最优的嵌套⽅案。

这个解法的关键在于,对于宽度 w 相同的数对,要对其⾼度 h 进⾏降序排序。因为两个宽度相同的信封不能相互包含的,逆序排序保证在 w 相同的数对中最多只选取⼀个。 

3.解答 
class Solution {
    //动态规划
    
    public int maxEnvelopes(int[][] envelopes) {
        int n = envelopes.length;
        //对二维数组进行降维:先对信封宽度w进行升序排序,简化为一维,然后对高度求最长上升子序列
        Arrays.sort(envelopes, new Comparator(){
            public int compare(int[] a, int[] b){
                //如果宽度相同,则按照高度降序排列,保证最多只有一个信封能用
                if(a[0] == b[0]){
                    return b[1] - a[1];
                }
                return a[0] - b[0];
            }
        });

        //对高度数组进行LIS
        int[] height = new int[n];
        for(int i = 0; i < n; i++){
            height[i] = envelopes[i][1];
        }
        
        return lengthOfLIS(height);
    }

    //辅助方法:二分搜索,类似于蜘蛛纸牌游戏,最后牌堆的堆数就是最长上升子序列的长度
    public int lengthOfLIS(int[] nums) {
        //top数组:表示牌堆
        int[] top = new int[nums.length];
        //牌堆数初始化为0
        int piles = 0;
        //依次处理每张牌
        for(int poker : nums){
            //
            int left = 0, right = piles;
            while(left < right){
                int mid = left + (right - left) / 2;
                if(top[mid] == poker){
                    right = mid;
                }else if(top[mid] > poker){
                    right = mid;
                }else if(top[mid] < poker){
                    left = mid + 1;
                }
            }
            ///
            //如果没找到合适的牌堆,就新建一堆
            if(left == piles){
                piles++;
            }
            //把这张牌放到对应的牌堆顶
            top[left] = poker;
        }
        //牌堆数就是最长上升子序列的长度
        return piles;
    }
}

时间复杂度为 O(NlogN) ,因为排序和计算 LIS 各需要 O(NlogN)的时间。空间复杂度为 O(N) ,因为计算 LIS 的函数中需要⼀个 top 数组。 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/777931.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号