数组的最长递增子序列
描述
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列:子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
约束条件
1 <= nums.length <= 2500
-104 <= nums[i] <= 104
思路:动态规划
- 定义数组
dp存储子问题的最优解,dp[i]表示以 以nums[i]结尾的子序列的最大长度
-
遍历
nums数组,求解dp[i]- 令
dp[i]的默认值为 1,在dp中向前遍历比nums[i]小的数nums[j],取max(num[j] + 1)
- 令
-
计算完
dp后,nums的最长升序子序列的长度为dp数组中的最大值
复杂度分析
- 时间复杂度:O(n2) ,遍历数组为 n,计算状态
dp[i]时,需要 O(n) 的时间遍历dp[0...i-1]的所有状态,所以总的时间为 O(n2)。
- 空间复杂度:O(n), 需要用到长度为 n 的
dp数组。
题解( C )
int lengthOfLIS(int* nums, int numsSize){
//辅助数组:存储nums[i]结尾的升序子序列最大长度
int dp[numsSize];
int max = 0;
for(int i = 0; i < numsSize; i++) {
dp[i] = 1;
for(int j = 0; j < i; j++) {
//当 nums[i] > nums[j],表示 i 可以放在 j之后形成更长的升序子序列
if(nums[i] > nums[j]) {
dp[i] = fmax(dp[j] + 1, dp[i]);
}
}
max = fmax(max, dp[i]);
}
return max;
}
题解( swift )
class Solution {
func lengthOfLIS(_ nums: [Int]) -> Int {
var dp = Array(repeating: 1, count: nums.count)
var maxA = 1
for (i, value) in nums.enumerated() {
for j in 0..<i {
if value > nums[j] {
dp[i] = max(dp[i], dp[j] + 1)
}
}
maxA = max(maxA, dp[i])
}
return maxA
}
}
进阶:求解最长递增子序列的个数
描述
给定一个未排序的整数数组,找到最长递增子序列的个数。
示例1:
输入: [1,3,5,4,7]
输出: 2
解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。
示例2:
输入: [2,2,2,2,2]
输出: 5
解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5。
约束条件
注意: 给定的数组长度不超过 2000 并且结果一定是32位有符号整数。
思路:动态规划
-
在求解 数组的最长递增子序列 的基础进行题解
-
新定义一个数组
cn,cn[i]表示以nums[i]为结尾的最长升序子序列的个数- 遍历
nums数组,计算dp[i]之后计算cn[i] cn[i]的值为所有满足dp[k] + 1 = dp[i] && nums[i] > nums[k] (0 <= k < i,)的cn[k]之和- 如果计算得出
cn[i]为 0,就给它设置为 1
- 遍历
- 计算完
cn后,nums的最长递增子序列的值为满足dp[i]值为最大升序子序列长度的cn[i]之和
复杂度分析
- 时间复杂度:O(n^2)
- 空间复杂度:O(n), 需要用到长度为 n 的
dp数组和cn数组。
题解( C )
int findNumberOfLIS(int* nums, int numsSize){
if(numsSize <=1) {
return 1;
}
int max = 1,res = 0;
int dp[numsSize], cn[numsSize];
for(int i = 0; i < numsSize; i++) {
dp[i] = 1;
for(int j = 0; j < i; j++) {
if(nums[i] > nums[j]){
dp[i] = fmax(dp[i],dp[j]+1);
}
}
max = fmax(dp[i],max);
//令 cn[i] 初始为 0
cn[i] = 0;
//计算满足 dp[j] + 1 = dp[i] && nums[i] > nums[j] 的 cn[j] 的和
for(int k = 0; k < i; k++) {
if(dp[i] == dp[k]+1 && nums[i] > nums[k]){
cn[i] += cn[k];
}
}
//如果没有以 nums[i] 为结尾的升序子序列,就将其设置为 1
if(cn[i] == 0) {
cn[i] = 1;
}
}
for(int i = 0; i<numsSize; i++) {
if(dp[i] == max) {
res += cn[i];
}
}
return res;
}
题解( swift )
class Solution {
func findNumberOfLIS(_ nums: [Int]) -> Int {
var dp = Array(repeating: 1, count: nums.count)
var cn = Array(repeating: 0, count: nums.count)
var maxA = 1,res = 0
for (i, value) in nums.enumerated() {
for j in 0..<i {
if value > nums[j] {
dp[i] = max(dp[i], dp[j] + 1)
}
}
maxA = max(maxA, dp[i])
for k in 0..<i {
if dp[k] + 1 == dp[i] && nums[i] > nums[k] {
cn[i] += cn[k]
}
}
cn[i] = cn[i] == 0 ? 1 : cn[i];
}
for (index, value) in cn.enumerated() {
if dp[index] == maxA {
res += cn[index]
}
}
return res
}
}