给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-increasing-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解法一:动态规划
class Solution {
/**
* 动态规划
* 1. 状态定义:f(n)=从index=0到index=n中最长的上升子序列
* 2. 转移方程:f(n)=f(x)+num[n], {f(0), f(1), ..., f(n-1)}过滤最后一个元素小于nums[n],并从中找出最长的上升子序列的f(x)
*
* @param nums
* @return
*/
public int lengthOfLIS(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int max = 1;
int[][] fn = new int[nums.length][];
fn[0] = new int[]{nums[0]};
for (int i = 1; i < nums.length; i++) {
int[] beforeMaxLengthOfLIS = findBeforeMaxLengthOfLIS(fn, i, nums[i]);
int newSize = beforeMaxLengthOfLIS != null ? beforeMaxLengthOfLIS.length + 1 : 1;
int[] curLIS;
if (beforeMaxLengthOfLIS == null) {
curLIS = new int[1];
} else {
curLIS = Arrays.copyOf(beforeMaxLengthOfLIS, newSize);
}
curLIS[newSize - 1] = nums[i];
fn[i] = curLIS;
if (newSize > max) {
max = newSize;
}
}
return max;
}
/**
* {f(0), f(1), ..., f(n-1)}过滤最后一个元素小于nums[n],并从中找出最长的上升子序列的f(x)
*
* @param fn
* @param curNum
* @return
*/
private int[] findBeforeMaxLengthOfLIS(int[][] fn, int endIndex, int curNum) {
int[] maxLength = null;
int max = 0;
for (int i = 0; i < fn.length; i++) {
int[] list = fn[i];
if (i >= endIndex || list[list.length - 1] >= curNum) {
continue;
}
if (list.length > max) {
max = list.length;
maxLength = list;
}
}
return maxLength;
}
}
解法二:定义一个最长上升子序列数组,只能添加或者更新,最终的长度就是最长的长度
class Solution {
/**
* 时间复杂度O(N*logN)
*
* @param nums
* @return
*/
public int lengthOfLIS(int[] nums) {
if (nums.length == 0) {
return 0;
}
List result = new ArrayList<>();
result.add(nums[0]);
for (int i = 1; i < nums.length; i++) {
// 当前元素大于数组中的所有元素,添加在尾部
if (result.get(result.size() - 1) < nums[i]) {
result.add(nums[i]);
continue;
}
// 二分查找,找到一个元素比当前元素大,前一个元素比当前元素小的元素,替换成当前元素
int begin = 0, end = result.size() - 1, mid;
do {
mid = (begin + end) / 2;
if (nums[i] > result.get(mid)) {
begin = mid + 1;
} else {
end = mid;
}
} while (begin < end);
result.set(begin, nums[i]);
}
return result.size();
}
public static void main(String[] args) {
int[] nums = {10, 9, 2, 5, 3, 4};
int result = new Solution().lengthOfLIS(nums);
System.out.println(result);
}
}