题目描述
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
所属题型
动态规划
该题目主要是要考虑到子序列中的元素在原数组中可以不是连续的,那么就需要依次遍历每个元素。
由于我是在刷力扣动态规划的相关题目遇到的这个题目,所以我在有意无意中也会往动态规划这个方向靠近,然后去解决这个问题。
题目分析
说到用动态规划,那就考虑状态转移方程,实际上对严格递增的子序列,我一般的做法是从小到大,从单个数据到一堆数组去考虑整个问题,因此对于单个数据本身就是一个严格递增的子序列,所以接下来的问题就是考虑如何对整个数组计算最长的严格递增子序列;
对于每个元素,其是否包含在某个严格递增子序列中依赖该元素之前的数据,所以,对于只有两个元素的数组,那么第一个元素的最长严格递增子序列就是本身 ,而第二个元素除了包含本身外,还要考虑其与第一个元素是否还能组成满足要求的子序列;
那么什么是满足要求呢?自然就是前一个元素严格小于当前元素,便能组成一个严格递增的子序列。
是因为同一个元素可以组成不同的子序列,而我们要做的就是依次查找我们需要的子序列。
解决过程
- 初始化dp数组,每个元素都能组成长度为1的子序列,因此dp数组的初始值都是1
- 依次遍历nums数组每个元素,依次向前检查能够组成严格递增子序列的元素,更新dp[i]
- 返回dp数组中的最大值,就是最终包含的严格递增子序列的最大长度。
java实现
class Solution {
/**
* 一次通过,嘻嘻嘻,使用动态规划算法,但是自认为时间复杂度有点高-O(n^2)
* @param nums
* @return
*/
public int lengthOfLIS(int[] nums) {
int len = nums.length;
int[] dp = new int[len];
// 初始化dp数组,每个单独的元素都是一个严格递增的关于nums数组的子序列,所以初始化dp数组都为1
for (int i = 0; i < len; i++) {
dp[i] = 1;
}
// 首先一次遍历每个元素,确定每个元素所在的dp数组的值
for (int i = 1; i < len; i++) {
// 依次从当前元素之前向前查找,主要查找nums数组值严格小于nums[i]的值,并且当其dp数组加1大于dp[i]的时候更新dp数组
// 因为不确定找到一个符合要求的值之后,前边是否还有满足条件的值,因此需要查到到数组起始位置,因此时间复杂度为O(n^2)
for (int j = i - 1; j >= 0; j--) {
if (nums[j] < nums[i] && dp[j] + 1 > dp[i]) {
dp[i] = dp[j] + 1;
}
}
}
// 查找完毕之后,将dp数组中的最大值返回即可
return Arrays.stream(dp).max().getAsInt();
}