刷题14 动态规划

文章介绍了几个与IT技术相关的问题,包括使用动态规划求解最小花费爬楼梯问题、连续天数的最高销售额、跳跃游戏的最少跳跃次数、以及最长递增子序列和最长公共子数组的长度计算,展示了如何运用递归和动态规划方法优化解决方案。
摘要由CSDN通过智能技术生成


LCR 088. 使用最小花费爬楼梯

数组的每个下标作为一个阶梯,第 i 个阶梯对应着一个非负数的体力花费值 cost[i](下标从 0 开始)。每当爬上一个阶梯都要花费对应的体力值,一旦支付了相应的体力值,就可以选择向上爬一个阶梯或者爬两个阶梯。

请找出达到楼层顶部的最低花费。在开始时,你可以选择从下标为 0 或 1 的元素作为初始阶梯。

输入:cost = [10, 15, 20]
输出:15
解释:最低花费是从 cost[1] 开始,然后走两步即可到阶梯顶,一共花费 15 。
int minCostClimbingStairs(int* cost, int costSize){
    int dp[costSize+1];
    //可以选择0/1作为开始,故都初始化为0
    dp[0]=0;
    dp[1]=0;
    //与两个状态都有关
    for(int i=2;i<=costSize;++i){
        dp[i]=fmin(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
    }
    return dp[costSize];
}


LCR 161. 连续天数的最高销售额

 某公司每日销售额记于整数数组 sales,请返回所有 连续 一或多天销售额总和的最大值。

要求实现时间复杂度为 O(n) 的算法。

输入:sales = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:[4,-1,2,1] 此连续四天的销售总额最高,为 6。

        相当于求最大连续子序列的和。

int maxSales(int* sales, int salesSize) {
    int n=salesSize;
    int ans=sales[0];
    int sum=0;
    for(int i=0;i<salesSize;++i){
        sum+=sales[i];
        ans=fmax(ans,sum);
        if(sum<0){
            sum=0;
        }
    }
    return ans;
}

45. 跳跃游戏 II

 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]

每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:0 <= j <= nums[i] 

i + j < n

输入: nums = [2,3,1,1,4] 输出: 2 解释: 跳到最后一个位置的最小跳跃数是 2。从下标为 0 跳到下标为 1 的位置,跳1步,然后跳 3步到达数组的最后一个位置。

int jump(int* nums, int numsSize) {
    int *dp=(int *)malloc(sizeof(int)*numsSize);
    //dp[i]: 表示能够到达i这个位置的最小次数
    dp[0]=0;
    for(int i=1;i<numsSize;i++ ){
        dp[i]=INT_MAX;
    }
    //枚举跳跃需要达到的范围
    for(int i=1;i<numsSize;++i){
        //找到达到i所需要的最短跳跃步数
        for(int j=0;j<i;++j){
            if(j+nums[j]>=i){
                dp[i]=fmin(dp[i],dp[j]+1);
            }        
        }
    }
    return dp[numsSize-1];
}

674. 最长连续递增序列 

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

连续递增的子序列 可以由两个下标 l 和 rl < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列

输入:nums = [1,3,5,4,7]
输出:3
解释:最长连续递增序列是 [1,3,5], 长度为3。
尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。 

        此题所求的递增序列必须是连续的,因此是简单题,也不需要动态规划,只需计数即可。

int findLengthOfLCIS(int* nums, int numsSize) {
    int ans=1;
    int count=1;
    for(int i=1;i<numsSize;++i){
        if(nums[i-1]<nums[i]){
            count++;
        }else{
            count=1;
        }
        ans=fmax(ans,count);
    }
    return ans;
}

300. 最长递增子序列 

给你一个整数数组 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 。

        所求的是子序列,可以是不连续的,因此需要动态规划,dp[i]是以下标i为结尾的最长递增子序列。 

int lengthOfLIS(int* nums, int numsSize) {
    int dp[numsSize];
    int ans=1;
    dp[0]=1;
    for(int i=1;i<numsSize;++i){
        dp[i]=1;//最小的递增序列就是一个数,因此初始化为1
        for(int j=0;j<i;++j){
            if(nums[j]<nums[i]){
                dp[i]=fmax(dp[i],dp[j]+1);//更新dp
            }
        } 
        ans=fmax(ans,dp[i]);
    }
    return ans;
}

 673. 最长递增子序列的个数

给定一个未排序的整数数组 nums , 返回最长递增子序列的个数 。

注意 这个数列必须是 严格 递增的。

输入: [1,3,5,4,7]
输出: 2
解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。

        此题为前一题的升级版,不仅要得出最长递增子序列的长度,还需要进行计数。 

int findNumberOfLIS(int* nums, int numsSize) {
    int dp[numsSize];//表示以i结尾的最长递增子序列的长度
    int cnt[numsSize];//表示以i结尾的最长递增子序列的个数
    int mmax=0,ans=0;
    for(int i=0;i<numsSize;++i){
        dp[i]=1;
        cnt[i]=1;
        for(int j=0;j<i;++j){
            if(nums[j]<nums[i]){
                if(dp[j]+1>dp[i]){
                    dp[i]=dp[j]+1;//最长的长度发生变化
                    cnt[i]=cnt[j];//重置计数
                }else if(dp[j]+1==dp[i]){
                    cnt[i]+=cnt[j];//最长子序列个数增加
                }
            }
        }
        if(dp[i]>mmax){
            //最大长度改变,更新mmax与ans
            mmax=dp[i];
            ans=cnt[i];
        }else if(dp[i]==mmax){
            //如果最大长度没变
            ans+=cnt[i];
        }
    }
    return ans;
}

718. 最长重复子数组

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

输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7]
输出:3
解释:长度最长的公共子数组是 [3,2,1] 。
int findLength(int* nums1, int nums1Size, int* nums2, int nums2Size) {
    int dp[nums1Size+1][nums2Size+1];
    //dp[i][j]为以i-1,j-1结尾的最长公共子数组
    memset(dp,0,sizeof(dp));
    int ans=0;
    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;
            }
            ans=fmax(ans,dp[i][j]);
        }
    }
    return ans;
}

 

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值