利用这个题目好好学习下动态规划,一直对动态规划不太理解。所以这边尽量以通俗易懂的语言将明白。

300最长上升子序列(LeetCode)

题目

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

示例:

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

说明:

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

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

解题思路:

image.png

  • 1、看了上图就很容易理解了,从10开始,长度为1;
  • 2、然后遍历到9,9比10要小,所以长度还是1;
  • 3、接着遍历到2,2比9、10都小,所以长度也是1;
  • 4、当遍历到5的时候,5比前面数组中的2要大,比9、10要小,所以长度更新为2;
  • 5、接着这样比下去。(比如当比较到7的时候,有两个序列的长度都是3,记录长度为就好)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.zhoujian.solutions.leetcode;

import java.util.Arrays;
import java.util.Scanner;

/**
 * @author zhoujian123@hotmail.com 2018/8/29 16:42
 */
public class LongIncreaseSubsequence {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        String[] s1 = s.split(" ");
        int[] nums = new int[s1.length + 1];
        for (int i = 0; i < s1.length; i++) {
            nums[i]= Integer.parseInt(s1[i]);
        }
        int n = lengthOfLIS(nums);
        System.out.println(n);
    }

    private static int lengthOfLIS(int[] nums) {

        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int len =nums.length,max=0;
        int[] dp = new int[len];
        for (int i = 0; i < len; i++) {
            //将数组初始化为1
            dp[i]=1;
            for (int j = 0; j < i; j++) {
                //如果后面的值大于前面的数字的值,并且dp的长度也大于j之前的值
                if (nums[i] > nums[j] && dp[j]+1 >dp[i]) {
                    //dp的长度加1
                    dp[i] = dp[j]+1;
                }
            }
            //更新此次循环的最大值
            max = Math.max(max,dp[i]);
        }
        return max;
    }
}

结果如下:

image.png

时间复杂度为O(n^2),空间复杂度为O(n)。

如果追求O(n log n)的话,可以尝试使用二分查找。