题目描述:
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例1:
输入:[10,9,2,5,3,7,101,18]
输出:4
解释:最长的上升子序列是 [2,3,7,101],它的长度是 4。
示例2:
输入:[0,1,0,3,2,3]
输出:4
解释:最长的上升子序列是 [0,1,2,3],它的长度是 4。
Java代码实现一:动态规划
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
int[] dp = new int[n];
Arrays.fill(dp, 1);
int max = 1;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
max = Math.max(max, dp[i]);
}
return max;
}
}
解决思路:
动态规划解决此题,定义dp[i]为以第i个数字结尾的最长递增子序列长度。
时间复杂度:
O(n^2)
Java代码实现二:贪心 + 二分查找
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
int len = 0;
for (int num : nums) {
int i = Arrays.binarySearch(dp, 0, len, num);
if (i < 0) {
i = -(i + 1);
}
dp[i] = num;
if (i == len) {
len++;
}
}
return len;
}
}
解决思路:
用一个数组dp记录最长递增子序列,其中dp[i]表示长度为i+1的递增子序列的最后一个数字。
时间复杂度:
O(nlogn)
Java代码实现三:树状数组
class Solution {
public int lengthOfLIS(int[] nums) {
if (nums.length == 0) {
return 0;
}
int n = nums.length;
int[] list = new int[n];
for (int i = 0; i < n; i++) {
list[i] = nums[i];
}
Arrays.sort(list);
for (int i = 0; i < n; i++) {
nums[i] = Arrays.binarySearch(list, nums[i]) + 1;
}
int[] c = new int[n + 1];
int max = 0;
for (int i = 0; i < n; i++) {
int res = query(c, nums[i] - 1);
max = Math.max(max, res + 1);
update(c, nums[i], res + 1);
}
return max;
}
public int lowbit(int x) {
return x & (-x);
}
public void update(int[] c, int pos, int val) {
while (pos < c.length) {
c[pos] = Math.max(c[pos], val);
pos += lowbit(pos);
}
}
public int query(int[] c, int pos) {
int res = 0;
while (pos > 0) {
res = Math.max(res, c[pos]);
pos -= lowbit(pos);
}
return res;
}
}
解决思路:
用树状数组,通过二进制最后一个1的位置,可以实现寻找子序列中小于等于某个数字的值的个数。
时间复杂度:
O(nlogn)
参考链接:
题解:最长递增子序列(动态规划、贪心 + 二分查找、树状数组)