leetcode300.最长递增子序列&&leetcode354.俄罗斯套娃信封问题(动态规划)

leetcode300.最长递增子序列

  • 题目:给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

    子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

  • 思路:

    • 定义一个dp备忘录数组,该数组的每一个下标对应的值表示从下标开始之前的最长递增子序列的数量。

    • 遍历二层循环,第一层从头开始遍历nums目标数组,第二层遍历从头到第一层的项,如果之前的项有小于当前项,则取dp数组当前项的下标值与(dp数组的小于当前项下标值+1)的最大值,直至循环结束。

    • 从头遍历dp数组,取数组中的最大值 即为最长递增子序列的数量

  • 时间复杂度:O(N的平方)

class Solution {
    public int lengthOfLIS(int[] nums) {
        //定义dp数组
        int[] dp = new int[nums.length];
        Arrays.fill(dp,1);
        int res = 0;
        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);
                }
             }
        }
​
        for(int k=0;k<dp.length;k++){
            res = Math.max(res,dp[k]);
        }
​
        return res;
    }
}

leetcode354.俄罗斯套娃信封问题

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

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

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

    注意:不允许旋转信封。

  • 思路:这是一个二维数组(宽度维度*高度维度)的求最长子序列长度。

    • 先对数组的宽度维度为从小到大排序,再对数组的高度维度从大到小排序(当宽度相同时,高度从大到小排序),然后对数组的高度维度求一维数组的最长递增子序列的数量即为最多信封的个数

class Solution {
    public int maxEnvelopes(int[][] envelopes) {
        int n = envelopes.length;
        //对二维数组先对宽度升序排序,再对高度进行降序排序
        Arrays.sort(envelopes,new Comparator<int[]>(){
            public int compare(int[] a,int[] b){
                return a[0]==b[0]?
                    b[1]-a[1]:a[0]-b[0];
            }
            
        });
​
        int[] height= new int[n];
        for(int i =0;i<n;i++){
            height[i] = envelopes[i][1];
        }
​
        return lengthOfLIS(height);
​
​
    }
​
    //更换二分查找算法,复杂度为O(N log(N))
    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;
        }
        // 牌堆数就是 最长递增子序列 长度
        return piles;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值