动态规划----7.最长递增子序列

300. 最长递增子序列 - 力扣(LeetCode)

/**

        动态规划O():

                maxSubseq[]:记录结果,maxSubseq[i],代表以下标为i的元素结尾,最长递增子序列的长度

                全部初始化为1,每个元素本身都是一个长度为1的子序列

                以下标为0结尾:maxSubseq[0] = 1; 只有一个元素只能是1

                以下标为1结尾:maxSubseq[1]---> if(nums[1] > nums[0]) ---> maxSubseq[0] + 1

                以下标为2结尾:maxSubseq[2]---> if(nums[2] > nums[0,1]) ---> Math.max(maxSubseq[0,1] + 1 )

                以下标为3结尾:maxSubseq[3]---> if(nums[3] > nums[0,1,2]) ---> Math.max(maxSubseq[0,1,2] + 1 )

                .......

                以下标为i结尾:maxSubseq[i]---> if(nums[i] > nums[0...i-1]) ---> Math.max(maxSubseq[0...i-1] + 1 )

                即,比nums[i]小的元素(j)都进入待选,选择maxSubseq[j] + 1中最大的那个

        二分查找+贪心:

                维护一个List,遍历nums[],若nums[i] 大于List中的所有元素就将nums[i]插入到List的末尾

                若不大于List中的所有元素,则在List中找到第一个小于等于nums[i]的元素进行替换

            注意:

                由于可能后出现的元素替换之前的元素,该方法只能保证找到最长子序列的长度,但最终List中不一定是最长子序列

*/

class Solution {
    /**
        动态规划O():
                maxSubseq[]:记录结果,maxSubseq[i],代表以下标为i的元素结尾,最长递增子序列的长度
                全部初始化为1,每个元素本身都是一个长度为1的子序列

                以下标为0结尾:maxSubseq[0] = 1; 只有一个元素只能是1
                以下标为1结尾:maxSubseq[1]---> if(nums[1] > nums[0]) ---> maxSubseq[0] + 1 
                以下标为2结尾:maxSubseq[2]---> if(nums[2] > nums[0,1]) ---> Math.max(maxSubseq[0,1] + 1 )
                以下标为3结尾:maxSubseq[3]---> if(nums[3] > nums[0,1,2]) ---> Math.max(maxSubseq[0,1,2] + 1 )
                .......
                以下标为i结尾:maxSubseq[i]---> if(nums[i] > nums[0...i-1]) ---> Math.max(maxSubseq[0...i-1] + 1 )
                即,比nums[i]小的元素(j)都进入待选,选择maxSubseq[j] + 1中最大的那个

        二分查找+贪心:
                维护一个List,遍历nums[],若nums[i] 大于List中的所有元素就将nums[i]插入到List的末尾
                若不大于List中的所有元素,则在List中找到第一个小于等于nums[i]的元素进行替换
            注意:
                由于可能后出现的元素替换之前的元素,该方法只能保证找到最长子序列的长度,但最终List中不一定是最长子序列
    */
    public int lengthOfLIS(int[] nums) {
        //动态规划
        //return DP(nums);

        //二分查找+贪心
        return GreedyBinarySearch(nums);
    }

    //动态规划
    private int DP(int[] nums) {
        int len = nums.length;

        //maxSubseq[i],代表以下标为i的元素结尾,最长递增子序列的长度
        int maxSubseq[] = new int[len];

        //全部初始化为1,每个元素本身都是一个长度为1的子序列
        Arrays.fill(maxSubseq,1);

        //nums[i]小的元素(j)都进入待选,选择maxSubseq[j] + 1中最大的那个
        int maxLen = 1; //记录最长子序列
        for(int i = 0; i < len; i++) {
            for(int j = 0; j < i; j++) {
                if(nums[j] < nums[i]) {
                    maxSubseq[i] = Math.max(maxSubseq[i],maxSubseq[j] + 1); //过程中maxSubseq[i]中存储的是前[0,j - 1]最大的
                }
            }
            maxLen = Math.max(maxLen,maxSubseq[i]); //迭代记录
        }

        return maxLen;
    }

    //二分查找+贪心
    private int GreedyBinarySearch(int[] nums) {
        //维护一个List,辅助记录最长子序列长度
        List<Integer> tails = new ArrayList<>();

        //二分查找寻找nums中元素应该的位置
        for(int num : nums) {
            int left = 0, right = tails.size() - 1;
            //二分查找
            while(left <= right) {
                int mid = (left + right) / 2;
                if(tails.get(mid) < num) {
                    left = mid + 1;
                } else { //tails[mid] >= num 都向左半区搜索(找到第一个小于等于nums[i]的元素)
                    right = mid - 1; 
                }
            }

            //应该插入的位置就在最后
            if(left == tails.size()) {
                tails.add(num);
            } else { //进行替换
                tails.set(left,num);
            }
        }

        return tails.size();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值