开头先来一个小插曲,关于「最长递增子序列」问题的总结可见 动态规划设计:最长递增子序列
// 时间复杂度 : O(n^2)
// 空间复杂度 : O(n)
public int lengthOfLIS(int[] nums) {
int n = nums.length, ans = 0;
int[] dp = new int[n];
Arrays.fill(dp, 1);
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) dp[i] = Math.max(dp[i], dp[j] + 1);
}
ans = Math.max(ans, dp[i]);
}
return ans;
}
// 时间复杂度 : O(nlogn)
// 空间复杂度 : O(n)
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] top = new int[n];
int piles = 0;
for (int i = 0; i < n; i++) {
int poker = nums[i];
int l = 0, r = piles;
while (l < r) {
int m = l + r >> 1;
if (top[m] >= poker) r = m;
else l = m + 1;
}
if (l == piles) top[piles++] = poker;
else top[l] = poker;
}
return piles;
}
题目详情可见 最长上升子序列(三)
public int[] LIS (int[] nums) {
int n = nums.length;
// p 记录每个数在哪个堆中
int[] top = new int[n], p = new int[n];
int piles = 0;
for (int i = 0; i < n; i++) {
int poker = nums[i];
int l = 0, r = piles;
while (l < r) {
int m = l + r >> 1;
if (top[m] >= poker) r = m;
else l = m + 1;
}
if (l == piles) {
top[piles++] = poker;
p[i] = piles;
} else {
top[l] = poker;
p[i] = l + 1;
}
}
int[] ans = new int[piles];
for (int i = n - 1; i >= 0; i--) {
if (p[i] == piles) ans[--piles] = nums[i];
}
return ans;
}
public int[] LIS (int[] nums) {
int n = nums.length;
// p 记录每个数在哪个堆中
int[] top = new int[n], p = new int[n];
int piles = 0;
for (int i = 0; i < n; i++) {
int poker = nums[i];
int l = 0, r = piles;
while (l < r) {
int m = l + r >> 1;
// 反过来
if (top[m] < poker) r = m;
else l = m + 1;
}
if (l == piles) {
top[piles++] = poker;
p[i] = piles;
} else {
top[l] = poker;
p[i] = l + 1;
}
}
int cp = 0;
int[] ans = new int[piles];
// 正向遍历
for (int i = 0; i < n; i++) {
if (p[i] == cp + 1) ans[cp++] = nums[i];
}
return ans;
}