Given an unsorted array of integers, find the length of longest increasing subsequence.

    Example:

    1. Input: [10,9,2,5,3,7,101,18]
    2. Output: 4
    3. Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.

    Note:

    • There may be more than one LIS combination, it is only necessary for you to return the length.
    • Your algorithm should run in O(300. Longest Increasing Subsequence (M) - 图1) complexity.

    Follow up: Could you improve it to O(n log n) time complexity?


    题意

    找到一个无序数组中的最长递增子序列。

    思路

    1. 暴力法,直接使用dfs搜索;
    2. 对暴力法进行优化,将每一次dfs的结果记录下来;
    3. 动态规划。dp[i]代表以nums[i]为结尾的最长递增子数列的长度。针对一个i,遍历 j (j = 0, 1, …, i - 1),如果nums[i]>nums[j],说明可以将nums[i]添加到nums[j]后面构成一个新的递增子数列,其长度为dp[j]+1,这时候更新dp[i]为dp[i]和dp[j]+1之中较大的一个即可;
    4. 动态规划二分优化。遍历nums数组,针对每一个nums[i],用二分法查找它在dp数组中应该出现的位置x,如果该位置上已经有数,则更新dp[x]=nums[i];如果该位置上还没有数,则将nums[i]插入到该位置。

    代码实现 - dfs暴力

    1. class Solution {
    2. public int lengthOfLIS(int[] nums) {
    3. return dfs(nums, -1, 0);
    4. }
    5. private int dfs(int[] nums, int pre, int cur) {
    6. if (cur == nums.length) {
    7. return 0;
    8. }
    9. int use = (pre < 0 || nums[cur] > nums[pre]) ? 1 + dfs(nums, cur, cur + 1) : 0;
    10. int skip = dfs(nums, pre, cur + 1);
    11. return Math.max(use, skip);
    12. }
    13. }

    代码实现 - dfs优化

    1. class Solution {
    2. public int lengthOfLIS(int[] nums) {
    3. int[][] memo = new int[nums.length][nums.length];
    4. for (int[] list : memo) {
    5. Arrays.fill(list, -1);
    6. }
    7. return dfs(nums, -1, 0, memo);
    8. }
    9. private int dfs(int[] nums, int pre, int cur, int[][] memo) {
    10. if (cur == nums.length) {
    11. return 0;
    12. }
    13. if (memo[pre + 1][cur] >= 0) {
    14. return memo[pre + 1][cur];
    15. }
    16. int use = (pre < 0 || nums[cur] > nums[pre]) ? 1 + dfs(nums, cur, cur + 1, memo) : 0;
    17. int skip = dfs(nums, pre, cur + 1, memo);
    18. memo[pre + 1][cur] = Math.max(use, skip);
    19. return memo[pre + 1][cur];
    20. }
    21. }

    代码实现 - 动态规划

    1. class Solution {
    2. public int lengthOfLIS(int[] nums) {
    3. int[] dp = new int[nums.length];
    4. int maxLen = 0;
    5. for (int i = 0; i < nums.length; i++) {
    6. dp[i] = 1; // 初始值为1
    7. for (int j = 0; j < i; j++) {
    8. dp[i] = nums[i] > nums[j] ? Math.max(dp[i], dp[j] + 1) : dp[i];
    9. }
    10. maxLen = Math.max(maxLen, dp[i]);
    11. }
    12. return maxLen;
    13. }
    14. }

    代码实现 - 动态规划二分优化

    1. class Solution {
    2. public int lengthOfLIS(int[] nums) {
    3. List<Integer> dp = new ArrayList<>();
    4. for (int i = 0; i < nums.length; i++) {
    5. int pos = binarySearch(dp, nums[i]);
    6. if (pos == dp.size()) {
    7. dp.add(nums[i]);
    8. } else {
    9. dp.set(pos, nums[i]);
    10. }
    11. }
    12. return dp.size();
    13. }
    14. private int binarySearch(List<Integer> list, int target) {
    15. int left = 0, right = list.size() - 1;
    16. while (left <= right) {
    17. int mid = left + (right - left) / 2;
    18. if (list.get(mid) < target) {
    19. left = mid + 1;
    20. } else if (list.get(mid) > target) {
    21. right = mid - 1;
    22. } else {
    23. return mid;
    24. }
    25. }
    26. return left;
    27. }
    28. }