300. 最长递增子序列

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

  • 示例 1:

    1
    2
    3
    输入:nums = [10,9,2,5,3,7,101,18]
    输出:4
    解释:最长递增子序列是 [2,3,7,101],因此长度为 4
  • 示例 2:

    1
    2
    输入:nums = [0,1,0,3,2,3]
    输出:4
  • 示例 3:

    1
    2
    输入:nums = [7,7,7,7,7,7,7]
    输出:1
  • 提示:

    1. 1 <= nums.length <= 2500
    2. -104 <= nums[i] <= 104

题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 动态规划 + 二分查找
class Solution {
public int lengthOfLIS(int[] nums) {
int[] tails = new int[nums.length];
int res = 0;
for(int num : nums) {
int i = 0, j = res;
while(i < j) {
int m = (i + j) / 2;
if(tails[m] < num) i = m + 1;
else j = m;
}
tails[i] = num;
if(res == j) res++;
}
return res;
}
}

673. 最长递增子序列的个数

给定一个未排序的整数数组,找到最长递增子序列的个数。

  • 示例 1:
1
2
3
输入: [1,3,5,4,7]
输出: 2
解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。
  • 示例 2:
1
2
3
输入: [2,2,2,2,2]
输出: 5
解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5
  • 注意: 给定的数组长度不超过 2000 并且结果一定是32位有符号整数。

题 解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var findNumberOfLIS = function (nums) {
// 初始化dp数组
let len = nums.length;
let dp = Array(len).fill(1);
let count = Array(len).fill(1);
let res = 0;
// 找到最长子序列并做好标记
for (let i = 0; i < len; i++) {
for (let j = 0; j < i; j++) {
//只有这样才能出现更长的LIS 不明白就先去看LeetCode300题 题解
if (nums[i] > nums[j]) {
//第1种情况: LIS出现在以nums[j]结尾的地方而不是以nums[i]结尾的地方
if (dp[j] + 1 > dp[i]) {
dp[i] = dp[j] + 1;
count[i] = count[j];
} else if (dp[j] + 1 === dp[i]) {
//第2种情况: LIS同时出现在以nums[j]结尾的地方和以nums[i]结尾的地方
dp[i] = dp[i];
count[i] += count[j];
} else {
//第3种情况: LIS出现在以nums[i]结尾的地方而不是以nums[j]结尾的地方 (可以省略 写出来仅仅为了方便读者理解)
dp[i] = dp[i]
count[i] = count[i]
}
}
}
}
// 统计一下 max 出现的次数
let max = Math.max(...dp);
//这里想要统计所有LIS的个数就要遍历
for (let i = 0; i < len; i ++) if(dp[i] === max) res += count[i];
return res;
};