动态规划刷题思路
1.确认dp数组代表的含义
2.确认dp数组的算法公式
3.确认dp数组的初始值
4.确认循环开始和方向
5.验证dp数组含义
leetcode题目
一、爬楼梯-斐波那契数列
leetcode70 爬楼梯
1.dp数组代表,当前i有几种方法可以达到
2.dp[i]可以通过dp[i-1]往上爬一步,或者dp[i-2]往上爬2步达到
dp[i]=dp[i-1]+dp[i-2]
3.初始值:i从1开始 到n dp[1]=1,dp[2]=2
4.确认从1开始到n
代码:
- class Solution {
- public int climbStairs(int n) {
- if(n<3){
- return n;
- }
- //定义1个数组,数组类型为整数
- int[] dp=new int[n+1];
- dp[1]=1;
- dp[2]=2;
- for(int i=3;i
1;i++){ - dp[i]=dp[i-1]+dp[i-2];
- }
- return dp[n];
-
- }
- }
关注点:数组长度从索引0开始,但是取值从索引1开始,所以在定义数组长度时,为n+1
使用最小花费爬楼梯
索引:从0到n-1,需要达到的台阶索引为n
1.数组代表什么,代表达到当前索引需要的最小代价
2.数组算法:dp[i]等于dp[i-1]向上爬一步花费的cost[i-1]、dp[i-2]向上爬二步花费的cost[i-2]的最小值 ;dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2])
3.初始值:可以从0或1开始,所以dp[0]=0,dp[1]=0
4.遍历 从0开始 到n结束
- class Solution {
- public int minCostClimbingStairs(int[] cost) {
- int n=cost.length;
- int[] dp=new int[n+1];
- dp[0]=0;
- dp[1]=0;
- if(n<2){
- return 0;
- }
- for(int i=2;i
1;i++){ - dp[i]=Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
- }
- return dp[n];
-
- }
- }
二、不同路径-矩阵
不同路径
1.确认数组代表的含义:dp[i][j]=到达i*j矩阵的右下角有几种方式
2.算法公式 dp[i][j]= dp[i-1][j]+ dp[i][j-1]
3.初始值:dp[1][1]=1,dp[1][2]=1,dp[2][1]=1
初始化取值错误:dp[i][1]=1,dp[1][j]=1
4.遍历方法:从左到右
- class Solution {
- public int uniquePaths(int m, int n) {
- int[][]dp=new int[m+1][n+1];
- for(int i=1;i
1;i++){ - dp[i][1]=1;
- }
- for(int j=1;j
1;j++){ - dp[1][j]=1;
- }
- for(int i=2;i
1;i++){ - for(int j=2;j
1;j++){ - dp[i][j]= dp[i-1][j]+ dp[i][j-1];
- System.out.println(i+" "+j+" "+dp[i][j]);
- }
- }
- return dp[m][n];
-
- }
- }
不同路径II-有障碍物版本
具体思路,有障碍物的地方dp[i][j]数组等于0-因为无法到达这个路径
1.确定数组的含义:dp[i][j]到达i,j这个位置有多少条道路
2.dp[i][j]=dp[i-1][j]+ dp[i][j-1]
3.初始化取值:
3.1 dp[i][0]=1,dp[0][j]=1
3.2 dp[x][y]=0--原数组中等于1的位置
三、动态规划在字符串中的应用
最长回文子串
1.确认字符串的含义dp[i][j]代表s[i:j]是否为回文串
2.逻辑式:dp[i+1][j-1]=true&&dp[i]==dp[j]
3.初始值:i=j时,肯定是,j=i+1,相等的时候是
4.遍历方法:从左到右 j从i开始
- class Solution {
- public String longestPalindrome(String s) {
- int n = s.length();
- if (n < 2) {
- return s;
- }
- int max_len = 1;
- int begin = 0, end = 0;
- boolean[][] dp = new boolean[n][n];
-
- // 每个字符自身肯定是一个回文
- for (int i = 0; i < n; i++) {
- dp[i][i] = true;
- }
-
- // 检查所有长度为2的子串
- for (int i = 0; i < n - 1; i++) {
- if (s.charAt(i) == s.charAt(i + 1)) {
- dp[i][i + 1] = true;
- max_len = 2;
- begin = i;
- end=i+1;
- }
- }
-
- // 检查长度大于2的子串
- for (int len = 3; len <= n; len++) {
- for (int i = 0; i <= n - len; i++) {
- int j = i + len - 1;
- if (dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j)) {
- dp[i][j] = true;
- if (len > max_len) {
- max_len = len;
- begin = i;
- end = j;
- }
- }
- }
- }
-
- // 构建最长回文子串
- return s.substring(begin, end + 1);
- }
- }
最长回文子序列
评论记录:
回复评论: