每日一题
今天继续来练习动态规划
题目要求
给你一个整数数组 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
题目解析
这道题很明显是需要用动态规划来解决的,那么该如何定义dp数组来解决这道题呢?
这道题求的是最长的递增子序列,dp数组每一位上表达一定是子序列的最大长度,我最开始的想法是用dp[i]来表示从开始到第i位为止,这几位中最长的递增子序列长度。
后来又想了想,这样做不现实,因为需要考虑到后面的情况,前面记录的最长子序列加上后面一部分不一定会得到整个数组的最长子序列,相反可能前面没有记录的几个数字可能会和后面的部分组成最长的递增子序列。
例如数组[7,8,1,9,10,2,3,4,5,6]
如果按我开始的想法,到10的时候记录下的最长子序列一定是7,8,9,10长度为4,当时前面的1可以和后面的2,3,4,5,6组成更长的子序列,长度为6。因此这种想法不可行。需要转变思路。
既然这样不行,我可以让dp[i]表达在一定有nums[i]的情况下,截至到第i位可以组成的最长子序列。这样求完后只需要在统计一个dp数组中的最大值即可得到最长的递增子序列。
例如数组[10,9,2,5,3,7,101,18]
其可以得到的dp数组为[1,1,1,2,2,3,4,1],尤此就可以发现最长的子序列长度为4.
具体操作只需要比遍历到nums[i]时,查找dp[0]到dp[i-1]中最大的且在nums中小于nums[i]的。
代码实现
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp =new int[nums.length];
dp[0]=1;
for(int i=1;i<nums.length;i++){
int cur = nums[i];
int max = 0;
for(int j=0;j<i;j++){
if(nums[j]<cur&&dp[j]>max) max = dp[j];
}
dp[i]=max + 1;
}
int res =0;
for(int x:dp){
if(x>res) res = x;
}
return res;
}
}