欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

LeetCode 题解之 300. Longest Increasing Subsequence(最长上升子序列 LIS)

程序员文章站 2022-06-06 15:51:14
...

300. Longest Increasing Subsequence

题目描述和难度

  • 题目描述:

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4

说明:

  • 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
  • 你算法的时间复杂度应该为 O(n2) 。

进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

思路分析

求解关键:

思路1:使用动态规划。
状态的定义:以 num[i] 结尾的最长上升子序列的长度。
状态转移方程:之前的数中比 num[i] 小的最长上升子序列的长度 + 1。

思路2:使用贪心选择 + 二分查找算法。

LeetCode 题解之 300. Longest Increasing Subsequence(最长上升子序列 LIS)

LeetCode 题解之 300. Longest Increasing Subsequence(最长上升子序列 LIS)

LeetCode 题解之 300. Longest Increasing Subsequence(最长上升子序列 LIS)

参考解答

参考解答1

import java.util.Arrays;

// 最长上升子序列问题
// 300. 最长上升子序列
// https://leetcode-cn.com/problems/longest-increasing-subsequence/description/
public class Solution {

    //【关键】将 dp 数组定义为:以 nums[i] 结尾的最长上升子序列的长度
    // 那么题目要求的,就是这个 dp 数组中的最大者
    // 以数组  [10, 9, 2, 5, 3, 7, 101, 18] 为例:
    // dp 的值: 1  1  1  2  2  3  4    4
    // 注意实现细节。
    public int lengthOfLIS(int[] nums) {
        int len = nums.length;
        if (len == 0) {
            return 0;
        }
        // 状态的定义是:以 i 结尾的最长上升子序列的长度
        // 状态转移方程:之前比最后那个数字小的最长上升子序列的长度 + 1
        int[] dp = new int[len];
        Arrays.fill(dp, 1); // 如果只有 1 个元素,那么这个元素自己就构成了最长上升子序列,所以设置为 1 是合理的
        for (int i = 1; i < len; i++) { // 从第 2 个元素开始,逐个写出 dp 数组的元素的值
            int curVal = nums[i];
            for (int j = 0; j < i; j++) { // 找出比当前元素小的哪些元素的最小值
                if (curVal > nums[j]) {
                    dp[i] = Integer.max(dp[j] + 1, dp[i]);
                }
            }
        }
        // 最后要全部走一遍,看最大值
        int res = dp[0];
        for (int i = 0; i < len; i++) {
            res = Integer.max(res, dp[i]);
        }
        return res;
    }

    public static void main(String[] args) {
        int[] nums = {10, 9, 2, 5, 3, 7, 101, 18};
        Solution solution = new Solution();
        int lengthOfLIS = solution.lengthOfLIS(nums);
        System.out.println(lengthOfLIS);
    }
}

参考解答2

import java.util.Arrays;

public class Solution4 {

    // 有贪心选择的意思
    public int lengthOfLIS(int[] nums) {
        int len = nums.length;
        // 先考虑极端输入
        if (len <= 1) {
            return len;
        }
        // tail 数组的定义:长度为 i+1 的上升子序列的末尾最小是几
        int[] tail = new int[len];
        // 遍历一遍整个数组,使用二分查找算法
        tail[0] = nums[0];
        int res = 0;
        for (int i = 1; i < len; i++) {
            // 比 tail 数组实际有效的末尾的那个元素还大
            if (nums[i] > tail[res]) {
                // 直接添加在那个元素的后面
                tail[++res] = nums[i];
            } else {
                // 二分查找到第 1 个比 nums[i] 还大的元素,更新到那个位置
                int l = 0;
                int r = res;
                while (l < r) {
                    int mid = l + (r - l) / 2;
                    // 有就啥都不做了
                    if (tail[mid] == nums[i]) {
                        l = mid;
                        break;
                    } else if (tail[mid] >= nums[i]) {
                        r = mid;
                    } else {
                        l = mid + 1;
                    }
                }
                tail[l] = nums[i];
            }
            printArray(nums[i], tail);
        }
        return ++res;
    }

    // 调试方法,以观察是否运行正确
    private void printArray(int num, int[] tail) {
        System.out.print("当前数字:" + num);
        System.out.print("\t当前 tail 数组:");
        int len = tail.length;
        for (int i = 0; i < len; i++) {
            if (tail[i] == 0) {
                break;
            }
            System.out.print(tail[i] + ", ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int[] nums = new int[]{3, 5, 6, 2, 5, 4, 19, 5, 6, 7, 12};
        Solution4 solution4 = new Solution4();
        int lengthOfLIS = solution4.lengthOfLIS(nums);
        System.out.println("最长上升子序列的长度:" + lengthOfLIS);
    }
}

本篇文章的地址为 https://liweiwei1419.github.io/leetcode-solution/leetcode-0300-longest-increasing-subsequence ,如果我的题解有错误,或者您有更好的解法,欢迎您告诉我 [email protected]


.label-warning {
background-color: #f0ad4e;
}

.label-success {
    background-color: #5cb85c;
}

.label-danger {
    background-color: #d9534f;
}

.label {
    display: inline;
    padding: .2em .6em .3em;
    font-size: 75%;
    font-weight: 700;
    line-height: 1;
    color: #fff;
    text-align: center;
    white-space: nowrap;
    vertical-align: baseline;
    border-radius: .25em;
}
相关标签: LIS leetcode