leedcode题解-动态规划

递归和动态规划都是将原问题拆成多个子问题然后求解,他们之间最本质的区别是,动态规划保存了子问题的解,避免重复计算。

1、爬楼梯

70. Climbing Stairs (Easy)

3、矩阵的最小路径和

64. Minimum Path Sum (Medium)

思路:创建与grid相同大小的dp表,dp[i][j]表示从(0,0)到(i,j)的最短路径。由于第0行上的值只能由左边的值往右移,第0列的值只能由上面的值往下移。因此第0行第0列的值可直接填入。因为dp[i][j]的值可由dp[i-1][j]下移或dp[i][j-1]右移得到,此时要计算两者之间的最小值,dp[i][j]=min(dp[i-1][j],dp[i][j-1]);此时需要填满整张dp表,最右下角的值即为所求。矩阵一共有M*N个位置,每个位置都要计算一次最小路径,因此时间复杂度为O(M*N),空间复杂度也为O(M*N)。

空间压缩后的动态规划方法:定义一个动态滚动数组,每一行都更新每个位置的最小路径。空间复杂度即为O(N),

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        if(grid.empty())
            return 0;
        int rows=grid.size();
        int cols=grid[0].size();
        vector<vector<int>>dp;
        dp.resize(rows,vector<int>(cols));//初始化dp与grid相同大小
        dp[0][0]=grid[0][0];
        for(int i=1;i<rows;i++){
            dp[i][0]=dp[i-1][0]+grid[i][0];
        }
        for(int j=1;j<cols;j++){
            dp[0][j]=dp[0][j-1]+grid[0][j];
        }
        for(int i=1;i<rows;i++){
            for(int j=1;j<cols;j++){
                dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];
            }
        }
        return dp[rows-1][cols-1];
    }
};



class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        if(grid.empty())
            return 0;
        int rows=grid.size();int cols=grid[0].size();
        vector<int>dp(cols);
        for(int i=0;i<rows;i++){
            for(int j=0;j<cols;j++){
                if(j==0)
                    dp[j]=dp[j];//第一列的值都是从上一行复制下来的
                else if(i==0){
                    dp[j]=dp[j-1];//第一行的值都是左侧的值复制过来的
                }
                else
                    dp[j]=min(dp[j-1],dp[j]);
              //在上一行中当前位置的值与当前位置的左侧的值的较小值中取较小值
                dp[j]+=grid[i][j];
            }
        }
        return dp[cols-1];
    }
};

4、矩阵的总路径数

62. Unique Paths (Medium)

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

问总共有多少条不同的路径?

class Solution {
public:
    int uniquePaths(int m, int n) {
        if(m<=0||n<=0)
            return 0;
        vector<vector<int>>dp;
        dp.resize(m,vector<int>(n));
        for(int i=0;i<m;i++){
            dp[i][0]=1;//第一列的每一行只能由上往下到达
        }
        for(int j=0;j<n;j++){
            dp[0][j]=1;//第一行的每一列只能从左向右到达,只有一条路径
        }
        for(int i=1;i<m;++i){
            for(int j=1;j<n;j++){
                dp[i][j]=dp[i-1][j]+dp[i][j-1];//可以从左侧进入,也可以从上面进入
            }
        }
        return dp[m-1][n-1];
    }
};

5、数组区间和

303. Range Sum Query - Immutable (Easy)

class NumArray {
public:
    vector<int>sum;
    NumArray(vector<int> nums) {
        sum.push_back(0);
        for(int i=1;i<=nums.size();i++){
            sum.push_back(nums[i-1]+sum[i-1]);
        }
    }
    
    int sumRange(int i, int j) {
        return sum[j+1]-sum[i];
    }
};

/**
 * Your NumArray object will be instantiated and called as such:
 * NumArray* obj = new NumArray(nums);
 * int param_1 = obj->sumRange(i,j);
 */

6、等差数列划分

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
        if(A.empty())
            return 0;
        vector<int>dp(A.size());
        for(int i=2;i<A.size();++i){
            if(A[i]-A[i-1]==A[i-1]-A[i-2])
                dp[i]=dp[i-1]+1;//已i-1结尾的等差数列满足A[i-1]-A[i-2]==A[i-2]A[i-3],因此i,i-1,i-2,i-3也是等差数列,所以以i结尾的等差数列是i-1结尾的等差数列的延伸,加上i与它前面两个数构成的等差数列。
        }
        int count=0;
        for(int t:dp){
            count+=t;
        }
        return count;
    }
};

7、分割整数的最大乘积

343. Integer Break (Medim)

class Solution {
public:
    int integerBreak(int n) {
        if(n<=0)
            return 0;
        vector<int>dp(n+1);
        dp[1]=1;
        dp[2]=1;
        for(int i=3;i<=n;i++){
            for(int j=1;j<=i-1;j++){
                dp[i]=max(dp[i],max(j*dp[i-j],j*(i-j)));
            }
        }
        return dp[n];
    }
};

8、v按平方数来分割整数

279. Perfect Squares(Medium)

class Solution {
public:
    int numSquares(int n) {
        if(n<=0)
            return 0;
        vector<int>square=Squarenum(n);
        vector<int>dp(n+1);
        dp[1]=1;
        for(int i=2;i<=n;i++){
            int minnum=INT_MAX;
        for(int j=0;j<square.size();j++){
            if(square[j]>i)
                break;
             minnum=min(minnum,dp[i-square[j]]+1);
        }
            dp[i]=minnum;
        }
       return dp[n];
    }
    vector<int>Squarenum(int n){
        int i=1;
        int tmp=3;
        vector<int>res;
        while(i<=n){
            res.push_back(i);
            i+=tmp;
            tmp+=2;
        }
        return res;
    }
};

9、分割整数构成字母字符串

91. Decode Ways (Medium)

class Solution {
public:
    int juge1(char a){
        int sum=(a-'0');
        return sum<=26&&sum>0?1:0;
    }
    int juge2(char a,char b){
        int sum=(a-'0')*10+b-'0';
        return sum>26||sum<=0||a=='0'?0:1;
    }
    int numDecodings(string s) {
        if(s.length()==0)
            return 0;
        if(s[0]=='0')
            return 0;
        vector<int>dp(s.length(),0);
        dp[0]=juge1(s[0]);
        for(int i=1;i<s.size();i++){
            if(i-2>=0)
                dp[i]=(juge2(s[i-1],s[i])?dp[i-2]:0)+(juge1(s[i])?dp[i-1]:0);
            else
                dp[i]=(juge1(s[i])?dp[i-1]:0)+juge2(s[i-1],s[i]);
        }
        return dp[s.size()-1];
    }
};

10、最长递增子序列

300. Longest Increasing Subsequence (Medium)

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
         if(nums.empty())
             return 0;
        vector<int>dp(nums.size(),1);
        for(int i=1;i<nums.size();i++){
            for(int j=0;j<i;j++){
                if(nums[i]>nums[j])
                    dp[i]=max(dp[i],dp[j]+1);
            }
        }
        int max=0;
        for(int i=0;i<nums.size();i++){
            if(dp[i]>max)
                max=dp[i];
        }
        return max;
    }
};

11、一组整数对能够构成的最长链

646. Maximum Length of Pair Chain (Medium)

class Solution {
public:
    static bool cmp(vector<int>res1,vector<int>res2){
        return res1[0]<res2[0];
    }
    int findLongestChain(vector<vector<int>>& pairs) {
        if(pairs.empty())
            return 0;
        sort(pairs.begin(),pairs.end(),cmp);//按每一个数组的第一个值排序,因为每个数组的第二个值一定比第一个大
        vector<int>dp(pairs.size(),1);
        for(int i=1;i<pairs.size();i++){
            for(int j=0;j<i;j++){//比较i前面的每个位置上的最长连
                if(pairs[i][0]>pairs[j][1])
                    dp[i]=max(dp[i],dp[j]+1);
            }
        }
        int max=0;
        for(int i=0;i<dp.size();i++){
            if(dp[i]>max)
                max=dp[i];
        }
        return max;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值