数据结构与算法 leetcode刷题013 动态规划题型

今天开始刷数据结构与算法相应的体型:

为什么要提出动态规划,在递归问题中通常有很多循环递归的问题,导致在自上而下解决问题的时候递归的效率很低,运行的时间很长,所以就需要通过记忆化搜索的方式,将递归问题的解保存起来,这个过程称之为记忆化搜索的递归问题;通过记忆化搜索问题,进而知道递归过程的递推表达式,进而可以自下而上的寻求问题的解,这就是动态规划的思想;

leetcode70:爬楼梯的问题:

解法一:递归方式求解:

class Solution {
public:
    
    int climbStairs(int n) {
       //方法一 递归实现
        if(n==1){
            return 1;
        }
        if(n==2){
            return 2;
        }
        return climbStairs(n-1)+climbStairs(n-2);
     }
};

很遗憾leetcode提示超出了时间的LTE

解法二:采用记忆化搜索的方式;记忆化搜索就是通过一个数组来保存相应的解

由于需要测试代码,在leetcode中不能直接构建

解法三:采用动态规划的方式来构建,首先通过一个mem来存储相应的解,自底向上构建求解;

class Solution {
public:
    int climbStairs(int n) {
       //方法三 动态规划实现;
        vector<int> mem(n+1,-1);
        mem[0]=1;
        mem[1]=1;
        for(int i=2;i<=n;i++){
            mem[i]=mem[i-1]+mem[i-2];
        }
        return mem[n];
    }
};


leetcode120:在三角形中寻找一条和最小的路径,也是采用动态规划自底向上的方式;

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        //使用动态规划来保存相应的结果;将三角形对齐
        int row=triangle.size();
        if(row==0){
            return 0;
        }
        int column=triangle[row-1].size();
        vector<vector<int>> mem(row,vector<int>(column,0));
        //将最底层的元素填充进去;
        vector<int> lastRow=triangle[row-1];
        for(int i=0;i<lastRow.size();i++){
            mem[row-1][i]=lastRow[i];
        }
        for(int j=row-2;j>=0;j--){
            vector<int> temp2=triangle[j];
            for(int i=0;i<temp2.size();i++){
                mem[j][i]=min(mem[j+1][i]+triangle[j][i],mem[j+1][i+1]+triangle[j][i]);
            }
        }
        return mem[0][0];
    }
};


类似的还有相应的leetcode64中的题型,求解矩阵中的路径和最短;

leetcode64:一样也是从下到上得到相应的结果;

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
      //还是使用动态规划的思想来解决问题,自底向上的构建问题, 
    //使用一个数组来存储相应的解;
    int row=grid.size();
        if(row==0){
            return 0;
        }
    int column=grid[0].size();
    vector<vector<int>> mem(row,vector<int>(column,0));
    mem[row-1][column-1]=grid[row-1][column-1];
    for(int i=column-2;i>=0;i--){
        mem[row-1][i]=mem[row-1][i+1]+grid[row-1][i];
    }
    for(int j=row-2;j>=0;j--){
        mem[j][column-1]=mem[j+1][column-1]+grid[j][column-1];
    }
    //对于其他的值的部分
    for(int i=row-2;i>=0;i--){
        for(int j=column-2;j>=0;j--){
            mem[i][j]=grid[i][j]+min(mem[i+1][j],mem[i][j+1]);
        }
    }
    return mem[0][0];
    
    }
};


leetcode 343:使用动态规划来计算分解后的最大乘积;

class Solution {
public:
    int integerBreak(int n) {
        //使用动态规划的使用方式,用一个数组来保存相应的解,n=2时最大的乘积为1,n为3时最大的乘积为2,n等于4时 分解2,2 或者 1,3,如果继续分解 就使用存储好的值来进行运算 所以最大乘积为4
        if(n==0){
            return 0;
        }
        vector<int> mem(n+1,0);
        mem[1]=1;
        mem[2]=1;//使得mem[i] 就保存i分解后的成绩最大值
        for(int i=3;i<=n;i++){
            int maxNum=0;
            for(int j=1;j<=i/2;j++){
                maxNum=mymax(mem[j]*(i-j),mem[i-j]*j,j*(i-j),maxNum);
            }
            mem[i]=maxNum;
        }
        return mem[n];
    }
private:
    int mymax(int a,int b ,int c,int d){
    return max(max(a,d),max(b,c));
}
};


leetcode62: 求解机器人行走的路径的条数

class Solution {
public:
    int uniquePaths(int m, int n) {
        //动态规划的教科书的练习
        //还是使用动态规划的思想,自底向上解决问题
        //使用一个mem二维数组来构建mem[i][j] 表示从i,j出发能有多少条路径
        vector<vector<int>> mem(m,vector<int>(n,0));
        // mem[m-1][n-1]=1;
        for(int i=m-1;i>=0;i--){
            mem[i][n-1]=1;
        }
        for(int j=n-1;j>=0;j--){
            mem[m-1][j]=1;
        }
        for(int i=m-2;i>=0;i--){
            for(int j=n-2;j>=0;j--){
                mem[i][j]=mem[i][j+1]+mem[i+1][j];
            }
        }
        return mem[0][0];
        
    }
};

同样的了leetcode63 的方法也是类似的;这里就不再求解了,讨论一下有障碍的情况即可;


leetcode91 解析相应的字符串,自己没有解出来,主要是考虑的不全面,这里就贴了一下别人的解题思路,感觉总结的很好

https://blog.csdn.net/u012501459/article/details/46550815

可以看一下;


leetcode279:完美平方数 之前采用的是图的层序遍历的方式,上次的运行时间是52ms

采用动态规划,

class Solution {
public:
    int numSquares(int n) {
        // int step=0;//建模实现,将所有节点:如果两个结点之间的数据差相差一个完全平方数,那么就在两个数据之间构造一条边
        // queue<pair<int ,int>> node;//第二个int表示的是行走的步数;
        // vector<bool> flag(n+1,false);//如果这个节点被访问过,那么下次不再进行访问;
        // node.push(make_pair(n,step));
        // while(!node.empty()){
        //     pair<int,int> top=node.front();
        //     step=top.second;
        //     int nums=top.first;
        //     node.pop();
        //     if(nums==0){
        //         return step;
        //     }
        //     for(int i=1;nums-i*i>=0;i++){
        //         if(flag[nums-i*i]==false){
        //             node.push(make_pair(nums-i*i,step+1));
        //             flag[nums-i*i]=true;
        //         }
        //     }
        // }
        // return step;
        
        //如果使用动态规划来实现的话
        //自底向上构建
        //首先创建一个数组用来存储相应的值
        if(n==0){
            return 0;
        }
        // int m=n
        vector<int> mem(n+1,0);
        //从下到上依次遍历n
        mem[1]=1;
        for(int i=2;i<=n;i++){
            //寻找最近的平方数,最近平方数加一与原来的mem比较求小者
            mem[i]=i;
            for(int j=1;j*j<=i;j++){
                mem[i]=min(mem[i],mem[i-j*j]+1);
            }
        }
        return mem[n];
    }
};
运行的时间为110ms

猜你喜欢

转载自blog.csdn.net/hufanglei007/article/details/79665808