这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战
题目
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例
输入: nums = [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长递增子序列是 [2,3,7,101],因此长度为 4 。
输入: nums = [0,1,0,3,2,3]
输出: 4
输入: nums = [7,7,7,7,7,7,7]
输出: 1
提示
- 1 <= nums.length <= 2500
- <= nums[i] <=
解题思路
要求的最长严格递增子序列的长度,那这就代表当我们需要找到长度为n的子序列时,我们需要先确认n - 1的值,再对比前面子序列中的最大值是否小于当前元素,确认需否可以增加子序列长度。
代码实现
方法一:动态规划
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
// 每位元素自身长度为1
Arrays.fill(dp, 1);
int max = 1;
for(int i = 1; i < n; ++i){
for(int j = 0; j < i; ++j){
// 找到小于当前元素的元素位置,更新最大值
if(nums[j] < nums[i]){
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
// 更新最大值
max = Math.max(max, dp[i]);
}
// 返回结果
return max;
}
}
复杂度分析
- 时间复杂度:
- 空间复杂度:
方法二:动态规划 + 双指针
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
int ans = 0;
for(int num : nums){
// 这里 j = ans,取值 dp 数组右边界,逐步将 nums 数组中元素填充进 dp 数组
int i = 0, j = ans;
while(i < j){
// 取 dp 数组的中位数与当前元素进行比较
int mid = (i + j) / 2;
if(dp[mid] < num){
i = mid + 1;
}else{
j = mid;
}
}
// 更新 dp 数组中的值
dp[i] = num;
// 如果当前元素大于之前所有元素,则将边界向右扩展多一位
if(j == ans){
++ans;
}
}
// 返回最终结果
return ans;
}
}
复杂度分析
- 时间复杂度:
- 空间复杂度:
最后
文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!
如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!