【LeetCode】动态规划相关问题汇总

动态规划基础

70. 爬楼梯

题目描述

在这里插入图片描述

题解1 使用数组

class Solution {
public:
    int climbStairs(int n) {
        if(n<2)return n;
        vector<int>step(n+1);
        step[0]=1;
        step[1]=1;
        for(int i=2;i<n+1;i++)
        {
            step[i]=step[i-1]+step[i-2];
        }
        return step[n];

    }
};

题解2 两个临时变量

    int climbStairs(int n) {
        if(n<2)return n;;
        int tmp;
        int last1=1;
        int last2=1;
        for(int i=2;i<n+1;i++)
        {
            tmp=last1+last2;
            last2=last1;
            last1=tmp;
        }
  }

120. 三角形最短路径和

题目描述

在这里插入图片描述

题解1 两行变量记录 复杂度O(n)

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        int n=triangle.size();
        vector<int> lastbest(n,INT_MAX);
        vector<int> tmpbest(n,INT_MAX);
        lastbest[0]=triangle[0][0];
        tmpbest[0]=triangle[0][0];
        for(int i=1;i<n;i++)
        {
            for(int j=0;j<i+1;j++)
            {
                if(j==0)tmpbest[j]=lastbest[j]+triangle[i][j];
                else if(j<i)tmpbest[j]=min(lastbest[j]+triangle[i][j],lastbest[j-1]+triangle[i][j]);
                else 
                    tmpbest[j]=lastbest[j-1]+triangle[i][j];
                    //cout<<tmpbest[j]<<endl;
                
            }
            lastbest=tmpbest;
        }
        int ret=INT_MAX;
        for(int i=0;i<n;i++)
        {
            ret=min(ret,tmpbest[i]);
        }
        return ret;

    }
};

题解2 一行变量 自顶向下 空间复杂度O(n)

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        int n=triangle.size();
        vector<int> lastbest(n,INT_MAX);
        vector<int> tmpbest(n,INT_MAX);
        //lastbest[0]=triangle[0][0];
        tmpbest[0]=triangle[0][0];
        for(int i=1;i<n;i++)
        {
            for(int j=i;j>=0;j--)
            {
                if(j==0)tmpbest[j]=tmpbest[j]+triangle[i][j];
                else if(j<i)tmpbest[j]=min(tmpbest[j]+triangle[i][j],tmpbest[j-1]+triangle[i][j]);
                else 
                    tmpbest[j]=tmpbest[j-1]+triangle[i][j];
                    //cout<<tmpbest[j]<<endl;
                
            }
            //lastbest=tmpbest;
        }
        int ret=INT_MAX;
        for(int i=0;i<n;i++)
        {
            ret=min(ret,tmpbest[i]);
        }
        return ret;

    }
};

题解3 自底向上 不需要额外空间

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        int n=triangle.size();
        for(int i=n-2;i>=0;i--)
        {
            for(int j=0;j<triangle[i].size();j++)
            {
                triangle[i][j]=triangle[i][j]+min(triangle[i+1][j],triangle[i+1][j+1]);
            }
        }
        return triangle[0][0];

    }
};

343. 整数拆分

题目描述

在这里插入图片描述

题解1 动态规划

class Solution {
public:
    int max3(int x,int y,int z)
    {
        return x>y?x>z?x:z:y>z?y:z;
    }
    int integerBreak(int n) {
        vector<int> ret(n+1,0);
        ret[1]=1;
        for(int i=2;i<n+1;i++)
        {
            //cout<<"sdfdfs0"<<endl;
            for(int j=1;j<i;j++)
            {
                //cout<<(i-j)*ret[i-j]<<endl;
                ret[i]=max3((j)*ret[i-j],ret[i],(i-j)*(j));//(i-j)*(j)为i-j不拆分的情况
            }
        }
        return ret[n];
    }
};

279. 完全平方数

题目描述

在这里插入图片描述

题解1 使用队列进行图的遍历(时间较短)

题解2 动态规划

class Solution {
public:
    int numSquares(int n) {
        vector<int> ret(n+1,INT_MAX);
        ret[1]=1;
        ret[0]=0;
        for(int i=2;i<n+1;i++){
            for(int j=1;i-j*j>=0;j++)
            {
                ret[i]=min(ret[i],1+ret[i-j*j]);
            }
        }
        return ret[n];
    }
};

91. 解码方法

题目描述

在这里插入图片描述

题解1 难点在于分类讨论

class Solution {
public:
    int numDecodings(string s) {
        int n=s.size();
        vector<int> ret(n+1);
        
        if(s[0]=='0'){return 0;}
        else 
        {ret[0]=1;
        ret[1]=1;}
        for(int i=2;i<n+1;i++)
        {
            //if(s[i-1]=='0'&&s[i-2]=='0')return 0;
            if(s[i-1]=='0')
            {
               if(s[i-2]!='1'&&s[i-2]!='2') return 0;
               ret[i]=ret[i-2];
            }
            else if((s[i-2]=='2'&&s[i-1]>'6')||s[i-2]>'2'||s[i-2]=='0')
            {
                ret[i]=ret[i-1];
            }
            else
            {ret[i]=ret[i-2]+ret[i-1];}
        }
        return ret[n];
    }
};

62. 不同路径

题目描述

在这里插入图片描述

题解1

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> dp=vector<vector<int>>(m,vector<int>(n,0));
        
        for(int i=0;i<m;i++)
        {
            dp[i][0]=1;
        }
        for(int i=0;i<n;i++)
        {
            dp[0][i]=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];
    }
};

63. 不同路径 II

题目描述

在这里插入图片描述

题解1 额外空间

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int m=obstacleGrid.size();
        int n=obstacleGrid[0].size();
        vector<vector<int>> dp=vector<vector<int>>(m,vector<int>(n,0));
        
        for(int i=0;i<m;i++)
        {
            if(obstacleGrid[i][0]==1){dp[i][0]=0;break;}
            dp[i][0]=1;
        }
        for(int i=0;i<n;i++)
        {
            if(obstacleGrid[0][i]==1){dp[0][i]=0;break;}
            dp[0][i]=1;
        }
        for(int i=1;i<m;i++)
        {
            for(int j=1;j<n;j++)
            {
                if(obstacleGrid[i][j]==1){dp[i][j]=0;continue;}
                dp[i][j]=dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
};

题解2 不使用额外空间

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int m=obstacleGrid.size();
        int n=obstacleGrid[0].size();
        bool test=false;
        if(obstacleGrid[0][0]==1)test=true;
        int flag=false;
        for(int i=0;i<m;i++)
        {
            if(flag||obstacleGrid[i][0]==1){obstacleGrid[i][0]=0;flag=true;}
            else
            obstacleGrid[i][0]=1;
        }
        flag=test;
        for(int i=1;i<n;i++)
        {
            if(flag||obstacleGrid[0][i]==1){obstacleGrid[0][i]=0;flag=true;}
            else
            obstacleGrid[0][i]=1;
        }
        for(int i=1;i<m;i++)
        {
            for(int j=1;j<n;j++)
            {
                if(obstacleGrid[i][j]==1){obstacleGrid[i][j]=0;continue;}
                obstacleGrid[i][j]=obstacleGrid[i-1][j]+obstacleGrid[i][j-1];
            }
        }
        return obstacleGrid[m-1][n-1];
    }
};

状态定义和状态转移

198. 打家劫舍

题目描述

在这里插入图片描述

题解

class Solution {
public:
    int rob(vector<int>& nums) {
        int n=nums.size();

        if(n==0)return 0;
        vector<int> ret(n);
        ret[0]=nums[0];
        if(n==1)return nums[0];
        ret[1]=max(nums[0],nums[1]);
        for(int i=2;i<n;i++)
        {
            ret[i]=max(ret[i-2]+nums[i],ret[i-1]);
        }
        return ret[n-1];
    }
};

213. 打家劫舍 II

题目描述

在这里插入图片描述

题解1 使用两个变量 分别为偷了第一间和没偷第一间的最大值

class Solution {
public:
    int rob(vector<int>& nums) {
        int n=nums.size();

        if(n==0)return 0;
        vector<int> ret(n);
        vector<int> nret(n);
        nret[0]=0;
        ret[0]=nums[0];
        if(n==1)return nums[0];
        ret[1]=max(nums[0],nums[1]);
        nret[1]=max(nums[1],0);
        for(int i=2;i<n;i++)
        {
            ret[i]=max(ret[i-2]+nums[i],ret[i-1]);
            nret[i]=max(nret[i-2]+nums[i],nret[i-1]);
        if(i==n-1)
        ret[n-1]=max(ret[n-2],nret[n-3]+nums[n-1]);
        }
        
       // nret[n-1]=max()
        return ret[n-1];
    }
};

337. 打家劫舍 III

题目描述

在这里插入图片描述

题解1 两个变量 偷和不偷 可以使用pair类型

class Solution {
    
    pair<int,int> dfs(TreeNode* root)
    {
       //pair<int,int> ret=make_pair(0,0);
        if(root==NULL)return make_pair(0,0);
        pair<int,int> lmax=dfs(root->left);
        pair<int,int> rmax=dfs(root->right);

        return make_pair(lmax.second+rmax.second+root->val,max(lmax.first,lmax.second)+max(rmax.first,rmax.second));
        
    }
public:
    int rob(TreeNode* root) {
        //root->left
        pair<int,int> res=dfs(root);
        return max(res.first,res.second);
    }
};

面试中的背包问题

416. 分割等和子集

题目描述

在这里插入图片描述

题解1 记忆化搜索 bool类型

class Solution {
    bool helper(vector<int>&nums ,int c,int index,vector<vector<int>>&memo)
    {
        //cout<<c<<" "<<index<<endl;
        
        if(index<0||c<0)return false;
        if(c==0)return true;
        

        if(memo[index][c]!=-1)return memo[index][c]==1;

        memo[index][c]=(helper(nums,c,index-1,memo)||helper(nums,c-nums[index],index-1,memo))==1?1:0;
        return memo[index][c]==1;
        
    }
public:
    bool canPartition(vector<int>& nums) {
        int n=nums.size();
        int sum=0;
        for(int i=0;i<n;i++)
        {
            sum+=nums[i];
        }
        if(sum%2!=0)return false;
        //cout<<sum<<endl;
        vector<vector<int>>memo(n,vector<int>(sum/2+1,-1) );
        return helper(nums,sum/2,n-1,memo);
        
    }
};

题解2 动态规划

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int n=nums.size();
        int sum=0;
        for(int i=0;i<n;i++)
        {
            sum+=nums[i];
        }
        if(sum%2!=0)return false;
        vector<bool> ret(sum/2+1,false);
        sum=sum/2;
        //cout<<sum+1<<endl;
        for(int i=0;i<sum+1;i++)
        {
            ret[i]=(nums[0]==i);
            //cout<<i<<endl;
        }
        for(int i=1;i<n;i++)
        {
            for(int j=sum;j>=nums[i];j--)
            {
                //cout<<i<<' '<<j<<endl;
                ret[j]=(ret[j]||ret[j-nums[i]]);
            }
        }
        return ret[sum];
    }
};

322. 零钱兑换

题目描述

在这里插入图片描述

题解1 排序后提前结束

class Solution {//排序过了 提前跳过
public:
    int coinChange(vector<int>& coins, int amount) {
        int MAX=amount+1;
        vector<int> ret(amount+1,MAX);
        sort(coins.begin(),coins.end());
        ret[0]=0;
        for(int i=coins[0];i<amount+1;i++)
        {
            for(int j=0;j<coins.size()&&coins[j]<=i;j++)
            {
               
                ret[i]=min(1+ret[i-coins[j]],ret[i]);
            }
        }
        return ret[amount]==MAX?-1:ret[amount];
    }
};

题解2 没有排序

class Solution {//没有排序
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int> ret(amount+1,INT_MAX);
        sort(coins.begin(),coins.end());
        ret[0]=0;
        for(int i=coins[0];i<amount+1;i++)
        {
            for(int j=0;j<coins.size()&&coins[j]<=i;j++)
            {
                //cout<<i<<" "<<coins[j]<<endl;
                if(ret[i-coins[j]]==INT_MAX)
                {//cout<<'s'<<endl;
                continue;}
                //cout<<i<<"2"<<coins[j]<<endl;
                ret[i]=min(1+ret[i-coins[j]],ret[i]);
            }
        }
        return ret[amount]==INT_MAX?-1:ret[amount];
    }
};

377. 组合总和 Ⅳ

题目描述

在这里插入图片描述

题解1

class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        int n=nums.size();
        vector<unsigned long long>ret(target+1,0);
        ret[0]=1;
        for(int i=1;i<target+1;i++)
        {
            for(int j=0;j<nums.size();j++)
            {
                if(nums[j]<=i)
                {
                    ret[i]=ret[i]+ret[i-nums[j]];
                }
            }
        }
        return ret[target];
    }
};

474. 一和零

题目描述

题解 二维背包问题

139

494

LIS问题

300. 最长上升子序列

题目描述

在这里插入图片描述

题解1 动态规划 以n结尾的最长上升子序列

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n=nums.size();
        if(n==0)return 0;
        vector<int> res(n,1);
        int ret=1;
        for(int i=1;i<n;i++)
        {
            for(int j=0;j<i;j++)           
            {
                if(nums[i]>nums[j])
                {
                    //cout<<'a'<<endl;
                res[i]=max(res[i],res[j]+1);
                }
            }
        }
        
        for(int i=0;i<n;i++)
        {
            ret=max(ret,res[i]);
        }
        return ret;
    }
};

题解2 贪心算法+二分查找 难点在找upper bound

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int len = 1, n = (int)nums.size();
        if (n == 0) return 0;
        vector<int> d(n + 1, 0);
        d[len] = nums[0];
        for (int i = 1; i < n; ++i) {
            if (nums[i] > d[len]) d[++len] = nums[i];
            else{
                int l = 1, r = len, pos = 0; // 如果找不到说明所有的数都比 nums[i] 大,此时要更新 d[1],所以这里将 pos 设为 0
                while (l <= r) {
                    int mid = (l + r) >> 1;
                    if (d[mid] < nums[i]) {
                        pos = mid;
                        l = mid + 1;
                    }
                    else r = mid - 1;
                }
                d[pos + 1] = nums[i];
            }
        }
        return len;
    }
};

376. 摆动序列

题目描述

在这里插入图片描述

题解1 类似LIS

两个序列 值为以该元素为结尾的 一个是比上一个元素大 (上一个元素比上上个元素小的序列) 另一个是比上一个元素小(上一个元素比上上个元素大)的序列

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        int n=nums.size();
        if(n==0)return 0;
        vector<int> maxres(n,1);
        vector<int> minres(n,1);
        for(int i=1;i<n;i++)
        {
            for(int j=0;j<i;j++)
            {//相等直接跳过
                if(nums[i]>nums[j])
                {
                    maxres[i]=max(maxres[i],minres[j]+1);
                }
                else if(nums[i]<nums[j])
                {
                    minres[i]=max(minres[i],maxres[j]+1);
                }
            }
        }
        int ret=0;
        for(int i=0;i<n;i++)
        {
            ret=max(ret,maxres[i]);
            ret=max(ret,minres[i]);
        }
        return ret;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值