代码随想录第四十三天

发布于:2024-12-06 ⋅ 阅读:(113) ⋅ 点赞:(0)

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.最长连续递增序列

给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。

连续递增的子序列 可以由两个下标 lrl < 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.最长重复子数组

给两个整数数组 nums1nums2 ,返回 两个数组中 公共的 、长度最长的子数组的长度

示例 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;
}

反思

今天是子序列题目的第一天,我觉得最重要的还是理解子序列的遍历情况,以及如何实现找到最长的子序列这个操作。总体来说,难度还算适中。