牛客网动态规划练习专项版一(C++)

题目1(跳台阶)

描述
一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

数据范围:1 \leq n \leq 401≤n≤40
要求:时间复杂度:O(n)O(n) ,空间复杂度: O(1)O(1)
示例 1
输入:
2
复制
返回值:
2
复制
说明:
青蛙要跳上两级台阶有两种跳法,分别是:先跳一级,再跳一级或者直接跳两级。因此答案为2
示例 2
输入:
7
复制
返回值:
21

收获

对于本题,前提只有 一次 1 阶或者 2 阶的跳法。

a. 如果两种跳法,1 阶或者 2 阶,那么假定第一次跳的是一阶,那么剩下的是 n-1 个台阶,跳法是 f (n-1);

b. 假定第一次跳的是 2 阶,那么剩下的是 n-2 个台阶,跳法是 f (n-2)

c. 由 a\b 假设可以得出总跳法为: f (n) = f (n-1) + f (n-2)

d. 然后通过实际的情况可以得出:只有一阶的时候 f (1) = 1 , 只有两阶的时候可以有 f (2) = 2

e. 可以发现最终得出的是一个斐波那契数列:

          | 1, (n=1)

f(n) = | 2, (n=2)

          | f (n-1)+f (n-2) ,(n>2,n 为整数)

代码

class Solution {
public:
    int jumpFloor(int number) {
        if(number<=1){
            return 1;
        }
        int a=1;
        int b=1;
        int res=0;
        for(int i=2;i<=number;i++){
            res=(a+b);
            a=b;
            b=res;
        }
        return res;
    }
};

题目2(最小花费爬楼梯)

描述
给定一个整数数组 cost \cost ,其中 cost[i]\cost[i] 是从楼梯第i \i 个台阶向上爬需要支付的费用,下标从 0 开始。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

数据范围:数组长度满足 1 \le n \le 10^5 \1≤n≤10^5
,数组中的值满足 1 \le cost_i \le 10^4 \1≤cost
i
​
≤10
4

示例 1
输入:
[2,5,20]
复制
返回值:
5
复制
说明:
你将从下标为1的台阶开始,支付5 ,向上爬两个台阶,到达楼梯顶部。总花费为5
示例 2
输入:
[1,100,1,1,1,90,1,1,80,1]
复制
返回值:
6
复制
说明:
你将从下标为 0 的台阶开始。
1.支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
2.支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
3.支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
4.支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
5.支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
6.支付 1 ,向上爬一个台阶,到达楼梯顶部。
总花费为 6 。

收获

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param cost int整型vector 
     * @return int整型
     */
    int minCostClimbingStairs(vector<int>& cost) {
        // write code here
        vector<int >dp(cost.size()+1,0);
        for(int i=2;i<=cost.size();i++){
            dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
        }
        return dp[cost.size()];
    }
};

题目3(不同路径的数目1)

在这里插入图片描述
示例 1
输入:
2,1
复制
返回值:
1
复制
示例 2
输入:
2,2
复制
返回值:
2
复制

收获

代码

class Solution {
public:
    /**
     * 
     * @param m int整型 
     * @param n int整型 
     * @return int整型
     */
    int uniquePaths(int m, int n) {
        // write code here
        if(m==1||n==1)
            return 1;
        return uniquePaths(m-1,n)+uniquePaths(m,n-1);
    }
};

题目4(矩阵的最小路径和)

在这里插入图片描述
在这里插入图片描述
示例 1
输入:
[[1,3,5,9],[8,1,3,4],[5,0,6,1],[8,8,4,0]]
复制
返回值:
12
复制
示例 2
输入:
[[1,2,3],[1,2,3]]
复制
返回值:
7

收获

1:很大的收获是学会了对边缘数据的初始化

代码

class Solution {
public:
    /**
     * 
     * @param matrix int整型vector<vector<>> the matrix
     * @return int整型
     */
    int minPathSum(vector<vector<int> >& matrix) {
        // write code here
        int n=matrix.size();
        int m=matrix[0].size();
        vector<vector<int >> dp(n,vector<int>(m,0));
        //dp[i][j]表示以当前i,j位置为结尾的最短路径
        dp[0][0]=matrix[0][0];
        for(int i=1;i<n;i++)
            dp[i][0]=matrix[i][0]+dp[i-1][0];
        for(int i=1;i<m;i++)
            dp[0][i]=matrix[0][i]+dp[0][i-1];
        for(int i=1;i<n;i++)
            for(int j=1;j<m;j++){
                dp[i][j]=matrix[i][j]+(dp[i-1][j]>dp[i][j-1]?dp[i][j-1]:dp[i-1][j]);
            }
        return dp[n-1][m-1];
    }
};

题目5(兑换零钱1)

在这里插入图片描述

示例 1
输入:
[5,2,3],20
复制
返回值:
4
复制
示例 2
输入:
[5,2,3],0
复制
返回值:
0
复制
示例 3
输入:
[3,5],2
复制
返回值:
-1

收获

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 最少货币数
     * @param arr int整型vector the array
     * @param aim int整型 the target
     * @return int整型
     */
    int minMoney(vector<int>& arr, int aim) {
        // write code here
        if(aim==0)
            return 0;
        vector<int >dp(aim+1,aim+1);
        dp[0]=0;
        for(int i=1;i<=aim;i++)
            for(int j=0;j<arr.size();j++){
            //纸币的面额一定要小于当前要组成的aim值
                if(arr[j]<=i)
                    dp[i]=min(dp[i],dp[i-arr[j]]+1);
            }
        return dp[aim]>aim?-1:dp[aim];
    }
};

题目6(最长公共子序列二)

在这里插入图片描述示例 1
输入:
“1A2C3D4B56”,“B1D23A456A”
复制
返回值:
“123456”
复制
示例 2
输入:
“abc”,“def”
复制
返回值:
“-1”
复制
示例 3
输入:
“abc”,“abc”
复制
返回值:
“abc”
复制
示例 4
输入:
“ab”,“”
复制
返回值:
“-1”

收获

代码

class Solution {
public:
    /**
     * longest common subsequence
     * @param s1 string字符串 the string
     * @param s2 string字符串 the string
     * @return string字符串
     */
    string LCS(string s1, string s2) {
        // write code here
        int n1=s1.size();
        int n2=s2.size();
        vector<vector<string >>dp(n1,vector<string>(n2,""));
        //dp[i][j]表示当处理到s1的第i个元素和s2的第j个元素时公共子序列的长度
        
        for(int i=0;i<n1;i++)
            for(int j=0;j<n2;j++){
                if(i==0||j==0){
                    if(s1[i]==s2[j])
                        dp[i][j]=s1[i];
                }else if(s1[i]==s2[j]){
                    dp[i][j]=dp[i-1][j-1]+s1[i];
                }else{
                    dp[i][j]=dp[i][j-1].size()>dp[i-1][j].size()?dp[i][j-1]:dp[i-1][j];
                }
            }
        if(dp[n1-1][n2-1]=="")
            return "-1";
        return dp[n1-1][n2-1];
    }
};

题目7(最长公共子串)


示例 1
输入:
“1AB2345CD”,“12345EF”
复制
返回值:
“2345”
复制
备注:
1 \leq |str_1|, |str_2| \leq 5,0001≤∣str
1
​
∣,∣str
2
​
∣≤5000

收获

1:使用pos记录 位置,max记录长度的方法

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * longest common substring
     * @param str1 string字符串 the string
     * @param str2 string字符串 the string
     * @return string字符串
     */
    string LCS(string str1, string str2) {
        // write code here
        int n1=str1.size();
        int n2=str2.size();
        int max=0;
        int pos=0;
        vector<vector<int >>dp(n1+1,vector<int >(n2+1,0));
        for(int i=1;i<=n1;i++)
            for(int j=1;j<=n2;j++){
                if(str1[i-1]==str2[j-1]){
                    dp[i][j]=dp[i-1][j-1]+1;
                }else{
                    dp[i][j]=0;
                }
                if(dp[i][j]>max){
                    max=dp[i][j];
                    pos=i-1;
                }
            }
        return str1.substr(pos-max+1,max);
    }
};

题目8(把数字翻译成字符串)


示例 1
输入:
“12”
复制
返回值:
2
复制
说明:
2种可能的译码结果(”ab” 或”l”)
示例 2
输入:
“31717126241541717”
复制
返回值:
192
复制
说明:
192种可能的译码结果

收获

这道题主要是对 0 的处理,比如 00 这种是非法的,而 10 呢,则只有一种编码。
用 dp [i] 表示 s [0,…,i-1] 时的编码次数,那么:
如果 s [i-1] == ‘0’,dp [i] = 0,否则 dp [i] = dp [i-1];
接着再根据 s [i-1] s [i-2] 更新 dp [i]:
如果 s [i-1] == ‘1’,dp [i] += dp [i-2]
如果 s [i-1] == ‘2’&& s[i] <= 6,dp[i] += dp[i-2]

代码

class Solution {
public:
    /**
     * 解码
     * @param nums string字符串 数字串
     * @return int整型
     */
    int solve(string nums) {
        // write code here
        if(nums.size()==0||nums=="0")
            return 0;
        vector<int >dp(nums.size()+1,0);
        dp[0]=1;
        dp[1]=nums[0]=='0'?0:1;
        for(int i=2;i<=nums.size();i++){
            dp[i]=nums[i-1]=='0'?0:dp[i-1];
            if((nums[i-2]=='1')||((nums[i-2]=='2')&&(nums[i-1]<='6'))){
                dp[i]+=dp[i-2];
            }
        }
        return dp[nums.size()];
    }
};

题目9(最长上升子序列1)

在这里插入图片描述
示例 1
输入:
[6,3,1,5,2,3,7]
复制
返回值:
4
复制
说明:
该数组最长上升子序列为 [1,2,3,7] ,长度为4

收获

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 给定数组的最长严格上升子序列的长度。
     * @param arr int整型vector 给定的数组
     * @return int整型
     */
    int LIS(vector<int>& arr) {
        // write code here
        int n=arr.size();
        if(n==0)
            return 0;
        vector<int >dp(n,1);
        //dp[i]表示遍历到i的时候的严格上升的子序列的长度
        int res=0;
        for(int i=1;i<n;i++)
            for(int j=0;j<i;j++){
                if(arr[i]>arr[j]&&dp[i]<dp[j]+1){
                    dp[i]=dp[j]+1;
                    res=max(res,dp[i]);
                }
            }
        return res;
    }
};

题目10(连续数组的最大和)

在这里插入图片描述
示例 1
输入:
[1,-2,3,10,-4,7,2,-5]
复制
返回值:
18
复制
说明:
经分析可知,输入数组的子数组[3,10,-4,7,2]可以求得最大和为18
示例 2
输入:
[2]
复制
返回值:
2
复制
示例 3
输入:
[-10]
复制
返回值:
-10

收获

1:这里很重要的是不是直接返回dp[n-1],是需要在过程中寻找最大值的~

代码

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
        vector<int >dp(array.size(),0);
        dp[0]=array[0];
        int maxN=dp[0];
        for(int i=1;i<array.size();i++){
            dp[i]=max(dp[i-1]+array[i],array[i]);
            maxN=max(maxN,dp[i]);
        }
        return maxN;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值