赞
踩
目录
- 1.状态表示
-
- 是什么?dp表里的值所表示的含义
-
- 怎么来?1>.题目要求
-
- 2>题目要求+经验(这个为主要使用方法)
-
- 3>分析问题过程中发现重复子问题
-
- 2.状态转移方程
-
- dp[i]代表什么?
-
- 根据最近一步的状态表示
-
- 3.初始化
-
- 保证数组不越界
-
- 4.填表顺序,保证填写该状态时,所需要的状态已经计算过了
-
- 5.返回值
- 题目要求+状态表示
-
- (6.空间优化)
- 可以使用轮换数组来减少空间消耗,即使用有限个变量通过一轮轮赋值来向前推进

动态规划中要弄清楚每一步是为什么,多想想为什么
- 1.dp[i]表示第i给泰波那契数的值(题目给定)
-
- 2.dp[i] = dp[i-1] + dp[i-2] + dp[i-3]
-
- 3.将dp[0] dp[1] dp[2] 进行初始化
-
- 4.从左向右
- class Solution {
- public:
- int tribonacci(int n)
- {
- if(n == 0)return 0;
- if(n == 1 || n == 2)return 1;
-
- vector<int> dp(n+1);
- dp[0] = 0;
- dp[1] = 1;
- dp[2] = 1;
- for(int i = 3; i <= n; i++)
- {
- dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
- }
- return dp[n];
- }
- };

- class Solution {
- public:
- int waysToStep(int n)
- {
-
- if(n <= 2)return n;
- if(n == 3)return 4;
- vector<int> dp(n+1);
- dp[1] = 1;
- dp[2] = 2;
- dp[3] = 4;
- for(int i = 4;i <= n; i++)
- {
- dp[i] = ((dp[i-1] + dp[i-2])%(1000000007) + dp[i-3])%(1000000007);
- }
- return dp[n];
- }
- };

- 1.dp[i]表示爬到i位置时使用的最小花费
-
- 2.dp[i] = min( (dp[i-1] + cost[i - 1]), (dp[i-2] + cost[i - 2]) );
-
- 3.将dp[1] dp[2] 进行初始化
-
- 4.从左向右
- class Solution {
- public:
- int minCostClimbingStairs(vector<int>& cost) {
- int n = cost.size();
- vector<int> dp(n+1);
- for(int i = 2; i <= n; i++)
- {
- dp[i] = min( (dp[i-1] + cost[i-1]), (dp[i-2] + cost[i-2]) );
- }
- return dp[n];
- }
- };
- class Solution {
- public:
- int numDecodings(string s) {
- int size = s.size();
- vector<int> dp(size);
- if(s[0] == '0')return 0;
-
- if(s[0] > '0' && s[0] <= '9')dp[0] = 1;
- if(size <= 1)return dp[size-1];
-
- if(s[1] > '0' && s[1] <= '9')dp[1]++;
- int tmp = (s[0]-'0')*10 + s[1] - '0';
- if(tmp >= 10 && tmp <= 26)dp[1]++;
- if(size <= 2)return dp[size-1];
-
- for(int i = 2; i <= size - 1; i++)
- {
- if(s[i] > '0' && s[i] <= '9')dp[i] +=dp[i - 1];
- tmp = (s[i-1]-'0')*10 + s[i] - '0';
- if(tmp >= 10 && tmp <= 26)dp[i] += dp[i-2];
- }
- return dp[size-1];
- }
- };

- //使用虚拟节点优化后,初始化更加方便,但是需要注意映射关系
- class Solution {
- public:
- int numDecodings(string s) {
- int size = s.size();
- vector<int> dp(size+1);
- dp[0] = 1;//dp[0]等于1是因为,在循环判断中如果s[0]能与s[1]组合,它的解码方式就是一种,就
- //会加上dp[0]
- if(s[0] == '0')return 0;
- if(s[0] > '0' && s[0] <= '9')dp[1] = 1;
-
- for(int i = 2; i <= size; i++)
- {
- if(s[i - 1] > '0' && s[i - 1] <= '9')dp[i] +=dp[i - 1];
- int tmp = (s[i-1 - 1]-'0')*10 + s[i - 1] - '0';//映射关系改变,i 要整体减1
- if(tmp >= 10 && tmp <= 26)dp[i] += dp[i-2];
- }
- return dp[size];
-
- }
- };

使用虚拟位置的方法来确定填表
- class Solution {
- public:
- int uniquePaths(int m, int n) {
- vector<vector<int>> dp(m+1,vector<int>(n+1));
- dp[0][1] = 1;//因为[1][1]位置是初始位置,初始位置就算是一种情况,所以[0][1]处赋值为1
- for(int i = 1;i <= m; i++)
- {
- for(int j = 1;j <= n; j++)
- {
- dp[i][j] = dp[i][j-1] + dp[i-1][j];//下一格的路线是接在原路线上,算同一路线,所
- //以其路线总数就是左一格和上一格的路线之和
- }
- }
- return dp[m][n];
- }
- };

- class Solution {
- public:
- int uniquePathsWithObstacles(vector<vector<int>>& ob) {
- int m = ob.size();
- int n = ob[0].size();
- vector<vector<int>> dp(m+1,vector<int>(n+1));
- dp[0][1] = 1;
- for(int i = 1;i <= m; i++)
- {
- for(int j = 1;j <= n; j++)
- {
- if(ob[i-1][j-1] == 0)//主要思路同上,增加障碍物的判断
- dp[i][j] = dp[i][j-1] + dp[i-1][j];
- else dp[i][j] = 0;
- }
- }
- return dp[m][n];
- }
- };

- class Solution {
- public:
- int jewelleryValue(vector<vector<int>>& fm) {
- int m = fm.size();
- int n = fm[0].size();
- vector<vector<int>> dp(m+1,vector<int>(n+1));
- for(int i = 1; i <= m; i++)
- {
- for(int j =1;j <= n; j++)
- {
- dp[i][j] = max(dp[i-1][j],dp[i][j-1])+fm[i-1][j-1];//每次走之前选价值更大的,
- //其它同上面的题目
- }
- }
- return dp[m][n];
- }
- };

- 1.状态表示
- 下降到[i][j]的最小路径和
- 2.状态转移方程
- 前一行三个中位置的最小路径和+本位置的路径长度
- 3.初始化
- 先把全部位置初始化为INT_MAX,选择最小值时就不会影响到选值
- 把第一行初始化为0,计算第一行时初始值就是该位置的路径长度
- 4.填表顺序
- 从上到下从左到右
- 5.返回值 最后一行最小的
- class Solution {
- public:
- int minFallingPathSum(vector<vector<int>>& ma) {
- int m = ma.size()+ 1;
- int n = ma.size()+2;
- vector<vector<int>> dp(m,vector<int>(n,INT_MAX));
- for(int j = 0; j < n; j++)
- {
- dp[0][j] = 0;
- }
- for(int i = 1; i < m; i++)
- {
- for(int j = 1; j < n - 1; j++)
- {
- dp[i][j] = min(dp[i-1][j], min(dp[i - 1][j-1],dp[i-1][j+1]))+ ma[i-1][j-1];
- }
- }
- int tmp = INT_MAX;
- for(int j = 1; j < n -1; j++)
- {
- tmp = min(tmp,dp[m-1][j]);
- }
- return tmp;
- }
- };

- 1.状态表示
- dp[i][j]位置处到达终点所需要的最低健康点数,此处作为起点
- 如果某处作为终点,那么因为该处接受所需的健康点数与从该处出去之后所增加或减少的健康点数有关,因此不能依靠前一步确定这一步
- 2.状态转移方程
- dp[i][j] + dg[i][j] >= dp[i][j+1] 或
- dp[i][j] + dg[i][j] >= dp[i+1][j]
- 某一个位置到结束时后所需要的最低健康点数+此处的所得的健康点数(可能为负数) 要大于等于下一个位置到结束后需要的最低健康点数。取最小的值
- (终点实际上是右下角格子再向右或者向下一格,因为这个格子也有增加以及减少健康的判定)
- 如果某个地方提供的健康值很大,那么会出现即使通过这个地方之前勇士的健康值为负数他依旧可以顺利通过,但显然是不符合题意的,所以dp[i][j]>= 1,每次要与1取大
- 3.初始化
- 先把全部位置初始化为INT_MAX,选择最小值时就不会影响到选值
- 把右下角格子的右边以及下面的位置初始化为1,脱离右下角格字结束时最小的健康值为1,要保证勇士存活
- 4.填表顺序
- 从下到上从右到左
- 5.返回值dp[0][0]
- class Solution {
- public:
- int calculateMinimumHP(vector<vector<int>>& dg) {
- int m = dg.size();
- int n = dg[0].size();
- vector<vector<int>> dp(m+1,vector<int>(n+1, INT_MAX));
- dp[m][n-1] = 1;
- dp[m-1][n] = 1;
- for(int i = m - 1; i >=0; i--)
- {
- for(int j = n - 1; j >=0;j--)
- {
- dp[i][j] = min(dp[i][j+1], dp[i+1][j]) - dg[i][j];
- dp[i][j] = max(1,dp[i][j]);
- }
- }
- return dp[0][0];
- }
- };

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。