Longest Increasing Subsequence (M)
Given an unsorted array of integers, find the length of longest increasing subsequence.
Example:
Input: [10,9,2,5,3,7,101,18]
Output: 4
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(n2n^2n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
题意
找到一个无序数组中的最长递增子序列。
思路
- 暴力法,直接使用dfs搜索;
- 对暴力法进行优化,将每一次dfs的结果记录下来;
- 动态规划。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之中较大的一个即可;
- 动态规划二分优化。遍历nums数组,针对每一个nums[i],用二分法查找它在dp数组中应该出现的位置x,如果该位置上已经有数,则更新dp[x]=nums[i];如果该位置上还没有数,则将nums[i]插入到该位置。
代码实现 - dfs暴力
class Solution {
public int lengthOfLIS(int[] nums) {
return dfs(nums, -1, 0);
}
private int dfs(int[] nums, int pre, int cur) {
if (cur == nums.length) {
return 0;
}
int use = (pre < 0 || nums[cur] > nums[pre]) ? 1 + dfs(nums, cur, cur + 1) : 0;
int skip = dfs(nums, pre, cur + 1);
return Math.max(use, skip);
}
}
代码实现 - dfs优化
class Solution {
public int lengthOfLIS(int[] nums) {
int[][] memo = new int[nums.length][nums.length];
for (int[] list : memo) {
Arrays.fill(list, -1);
}
return dfs(nums, -1, 0, memo);
}
private int dfs(int[] nums, int pre, int cur, int[][] memo) {
if (cur == nums.length) {
return 0;
}
if (memo[pre + 1][cur] >= 0) {
return memo[pre + 1][cur];
}
int use = (pre < 0 || nums[cur] > nums[pre]) ? 1 + dfs(nums, cur, cur + 1, memo) : 0;
int skip = dfs(nums, pre, cur + 1, memo);
memo[pre + 1][cur] = Math.max(use, skip);
return memo[pre + 1][cur];
}
}
代码实现 - 动态规划
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
int maxLen = 0;
for (int i = 0; i < nums.length; i++) {
dp[i] = 1; // 初始值为1
for (int j = 0; j < i; j++) {
dp[i] = nums[i] > nums[j] ? Math.max(dp[i], dp[j] + 1) : dp[i];
}
maxLen = Math.max(maxLen, dp[i]);
}
return maxLen;
}
}
代码实现 - 动态规划二分优化
class Solution {
public int lengthOfLIS(int[] nums) {
List<Integer> dp = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
int pos = binarySearch(dp, nums[i]);
if (pos == dp.size()) {
dp.add(nums[i]);
} else {
dp.set(pos, nums[i]);
}
}
return dp.size();
}
private int binarySearch(List<Integer> list, int target) {
int left = 0, right = list.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (list.get(mid) < target) {
left = mid + 1;
} else if (list.get(mid) > target) {
right = mid - 1;
} else {
return mid;
}
}
return left;
}
}