300.最长递增子序列
给你一个整数数组 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]
为结尾的最长递增子序列的长度,初始时每个元素的值都为 1,因为每个元素至少可以形成一个长度为 1 的递增子序列。接着,使用两层循环,外层遍历数组中的每个元素,内层遍历当前元素之前的所有元素,判断是否可以形成递增子序列(即前一个元素小于当前元素)。如果可以,则更新 dp[i]
为 max(dp[i], dp[j] + 1)
,表示以当前元素为结尾的递增子序列的最大长度。最后,dp
数组中的最大值即为整个数组的最长递增子序列的长度。
解答:
int lengthOfLIS(int* nums, int numsSize) {
int* dp = malloc(sizeof(int)*numsSize);
for(int i = 0;i < numsSize;i++)
{
dp[i] = 1;
}
for(int i = 1;i < numsSize;i++)
{
for(int j = 0;j < i;j++)
{
if(nums[i]>nums[j])
{
dp[i] = fmax(dp[i],dp[j]+1);
}
}
}
int max = dp[0];
for(int i = 1;i < numsSize;i++)
{
if(dp[i] > max)
{
max = dp[i];
}
}
return max;
}
674.最长连续递增序列
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
连续递增的子序列 可以由两个下标 l
和 r
(l < r
)确定,如果对于每个 l <= i < r
,都有 nums[i] < nums[i + 1]
,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]]
就是连续递增子序列。
示例 1:
输入:nums = [1,3,5,4,7]
输出:3
解释:最长连续递增序列是 [1,3,5], 长度为3。
尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。
示例 2:
输入:nums = [2,2,2,2,2]
输出:1
解释:最长连续递增序列是 [2], 长度为1。
提示:
1 <= nums.length <= 104
-109 <= nums[i] <= 109
思路:
这道题跟上面的题目很相似,只不过这里是要连续的,所以我们直接用一层循环来解决,dp[i]
这里指代的是以nums[i]
结尾的连续最长递增序列,当满足递增且连续时,就在dp[i-1]
上加上1
代表又前进了一位,最后找出最大值就行了。
解答:
int findLengthOfLCIS(int* nums, int numsSize) {
int* dp = malloc(sizeof(int)*numsSize);
for(int i = 0;i < numsSize;i++)
{
dp[i] = 1;
}
int max = dp[0];
for(int i = 1;i < numsSize;i++)
{
if(nums[i] > nums[i-1])
{
dp[i] = dp[i-1]+1;
}
if(dp[i] > max)
{
max = dp[i];
}
}
return max;
}
718.最长重复子数组
给两个整数数组 nums1
和 nums2
,返回 两个数组中 公共的 、长度最长的子数组的长度 。
示例 1:
输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7]
输出:3
解释:长度最长的公共子数组是 [3,2,1] 。
示例 2:
输入:nums1 = [0,0,0,0,0], nums2 = [0,0,0,0,0]
输出:5
提示:
1 <= nums1.length, nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 100
思路:
这道题因为我们用这里给了我们两个数组,所以这里我们设置dp[i][j]
为nums1[i]
和nums2[i]
相同,nums1[j]
和nums2[j]
相同的数组递增次数,然后直接对每一个数组进行判断它们的元素是否相同,如果相同那么我们进行递增,如果不同我们就继续遍历,最后对这个数组进行最大值判断,找出最大值就行了。
解答:
int findLength(int* nums1, int nums1Size, int* nums2, int nums2Size) {
int** dp = calloc(nums1Size+1,sizeof(int*));
for(int i = 0;i < nums1Size+1;i++)
{
dp[i] = calloc(nums2Size+1,sizeof(int));
}
for(int i = 1;i <= nums1Size;i++)
{
for(int j = 1;j <= nums2Size;j++)
{
if(nums1[i-1] == nums2[j-1])
{
dp[i][j] = dp[i-1][j-1] + 1;
}
}
}
int max = dp[0][0];
for(int i = 0;i <= nums1Size;i++)
{
for(int j = 0;j <= nums2Size;j++)
{
if(max < dp[i][j])
{
max = dp[i][j];
}
}
}
return max;
}
反思
今天是子序列题目的第一天,我觉得最重要的还是理解子序列的遍历情况,以及如何实现找到最长的子序列这个操作。总体来说,难度还算适中。