题目链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
说明:
- 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
- 你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
解题思路:
一、维护数组存储最长子序列
- 当数组为空时或者当前值大于数组最后最后一个值,就直接插入
- 当当前值小于数组中最后一个值时,就把当前值和数组中当前值大于的第一个值进行替换
- 在查找数组中的当前值时,可以使用二分查找
/**
* @author: hyl
* @date: 2019/08/12
**/
public class Que300 {
//时间复杂度为O(N * logN),空间复杂度为O(N)
public int lengthOfLIS(int[] nums) {
if (nums == null || nums.length == 0){
return 0;
}
int[] res = new int[nums.length];
res[0] = nums[0];
int index = 0;
for (int i = 1; i < nums.length; i++) {
if (nums[i] > res[index]){
res[++index] = nums[i];
}else{
int indexNum = Arrays.binarySearch(res, 0, index, nums[i]);
if (indexNum >= 0){
res[indexNum] = nums[i];
}else{
//如果没找到,返回的是 -(mid + 1)
//需要看下二分查找的源码,这点有点坑,
//希望大家尽量可以使用自己写的,可以自定义自己返回的值
res[-indexNum-1] = nums[i];
}
}
}
return index+1;
}
public static void main(String[] args) {
new Que300().lengthOfLIS(new int[]{10,9,2,5,3,7,101,18});
}
}
总结:
- 时间复杂度为O(N * logN),空间复杂度为O(N)
- 如果不使用二分查找,则达不到O(N * logN),,只能退化成O(N *N)的算法
二、使用动态规划解决
- dp[i]保存到nums[i]最长的上升子序列的长度
- 每次求出最大的dp[i]即可
/**
* @author: hyl
* @date: 2019/08/12
**/
public class Que300 {
//dp求解
//时间复杂度为O(N * N),空间复杂度为O(N)
public int lengthOfLIS1(int[] nums) {
if (nums == null || nums.length == 0){
return 0;
}
int result = 1;
int[] dp = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
dp[i] = 1;
}
for (int i = 1; i < nums.length; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]){
dp[i] = Math.max(dp[j] + 1 , dp[i]);
}
}
result = Math.max(dp[i] , result);
}
return result;
}
public static void main(String[] args) {
new Que300().lengthOfLIS(new int[]{10,9,2,5,3,7,101,18});
}
}
代码地址:
https://github.com/Han-YLun/LeetCode/blob/master/Practice/src/Que300.java
文章为阿伦原创,如果文章有错的地方欢迎指正,大家互相交流。