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
和r
(l < 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;
}