今天开始刷数据结构与算法相应的体型:
为什么要提出动态规划,在递归问题中通常有很多循环递归的问题,导致在自上而下解决问题的时候递归的效率很低,运行的时间很长,所以就需要通过记忆化搜索的方式,将递归问题的解保存起来,这个过程称之为记忆化搜索的递归问题;通过记忆化搜索问题,进而知道递归过程的递推表达式,进而可以自下而上的寻求问题的解,这就是动态规划的思想;
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