动态规划从简单到入门

(4)字符串分割

给定一个字符串s和一个词典dict,确定s是否可以根据词典中的词分成一个或多个单词。
比如,给定
s = “leetcode”
dict = [“leet”, “code”]
返回true,因为"leetcode"可以被分成"leet code"

像这种问题,它会变得比较抽象不能直接给你直观的东西,需要我们分析出动态递归的过程。
子状态
1 字符满足
2 字符满足
。。
N 字符满足

F(i) 表示前i个字符满足 能被词典中的词分词
状态递推
字符数 真值表
0-1 true
0-2(0-1+2) true
0-3(0-2+3) true

0-n(0-n-1+n) true
当前字符n满足true时 小于i的字符都为true
J<i
F(f)&&dict.contains(s.substring(j,i))

返回结果
F(n)

import java.util.*;
public class Solution {
    public boolean wordBreak(String s, Set<String> dict) {
        boolean[] arr = new boolean[s.length()+1];
        if(s.length()==0){
            return false;
        }
          arr[0] = true;
        for(int i=1;i<=s.length();i++){
            for(int j=0;j<i;j++){
                if(arr[j]&&dict.contains(s.substring(j,i))){
                    arr[i] = true;
                    break;
                }
            
        }
    }
         return arr[s.length()];
    }
}

思路:要判断一个字符串n能不能被词典分割,判断过程 1个字符
2个字符 3个字符。。。。n个字符 都成立那么就可以被分割
不要陷入一个陷阱就是利用字典里面的字符串组,依次与字符串比较,这是一中错误的做法。

(5)三角矩阵

给定一个三角矩阵,找出自顶向下的最短路径和,每一步可以移动到下一行的相邻数字。
比如给定下面一个三角矩阵,自顶向下的最短路径和为11
在这里插入图片描述
通常我们理解可以将每一条从上到下的都写出来然后比较最小的一个
而采用动态规划的方式我们可以
状态
子状态
(0,0)…-…(n,n)的最短路径
F(i,j) = 从(0,0)到(i,j)最短路径和
状态递推
F(i,j) =Min(F(i-1,j-1),F(i-1,j))+now[i][j]
求当前的最短路径和就要知道前一个最短路径和加上分叉路最小值
初始值
F(0,0) = now[0][0]
返回结果
Min(F(n-1),i)

这里我们处理的方式为自底向上,这种方式的优点在于好理解,代码量小不用考虑边界问题,

import java.util.*;
public class Solution {
    public int minimumTotal(ArrayList<ArrayList<Integer>> triangle) {
      for (int i = triangle.size() - 2; i >= 0; i --) {
            for (int j = 0; j < triangle.get(i + 1).size() - 1; j ++) {
                int min = Math.min(triangle.get(i + 1).get(j), triangle.get(i + 1).get(j + 1));
                triangle.get(i).set(j, triangle.get(i).get(j) + min);
            }
        }
        return triangle.get(0).get(0);
    }
}

从目标开始 挑选预期相连的父亲中最小的一个min,将目标移动至父亲,再将值存入tr.get().get(i)+min,当移动值顶时 tr.get(0).get(0)中存放最小值
(6)路径总数
在一个m*n的网格的左上角有一个机器人,机器人在任何时候只能向下或者向右移动,
机器人试图到达网格的右下角,有多少可能的路径。
分析这道题关键在于 机器人的移动区间 当机器人处于第0行 第0列时 只能向右或者向下
状态
子状态 (0,0)----(m-1,n-1)
F(i,j) 从(0,0)到达F(i,j)路径数
状态递推
每次到达一个新位置,只能有两种方式
从上到达 F(i-1,j)
从右到达F(i,j-1)
F(i,j) =F(i-1,j)+F(i,j-1)
初始化
F(0,i) = 1
F(i,0) = 1
返回结果
F(m-1,n-1)

public class Solution {
    public int uniquePaths(int m, int n) {
            if(m*n==0){
                return 0;
            }
            int[][] sum = new int[m][n];
           for(int i=0;i<m;i++){
               sum[i][0] = 1;
           }
           for(int i=0;i<n;i++){
               sum[0][i] = 1;
           }
            for(int i=1;i<m;i++){
                for(int j=1;j<n;j++){
                    sum[i][j] = sum[i-1][j]+sum[i][j-1];
                }
            }
            return sum[m-1][n-1];
    }
}

特殊点在于初始值 要考虑边界问题,核心sum[i][j] = sum[i-1][j]+sum[i][j-1]; 核心在于到达目标的总路径数,等于从上到达的路径数加上从左到达

在之前的基础上 在网格中添加障碍物 用1表示

状态
子状态 从(0,0)------(m-1n-1)
F(i,j) 从(0,0)到F(i,j)的路径数
状态递推
F(I,J) = f(I-1,J)+F(I,J-1)
其中的特殊情况为 当在第0行有障碍物时 后面无法到达
当在第0列有障碍物时 后面无法到达
当F(i,j)有障碍物时 后面无法到达
初始化
F(0,i) = 1当在第0行有障碍物时 后面无法到达
F(0,j) = 1 当在第0列有障碍物时 后面无法到达
返回结果
F(m-1,n-1)

public class Solution {
    public int uniquePathsWithObstacles(int[][] obj) {
        if(obj==null){
            return 0;
        }
        int[][] arr = new int[obj.length][obj[0].length];
        for(int i=0;i<obj.length;i++){
            if(obj[i][0]==1){
                break;
            }else{
                arr[i][0] = 1;
            }
        }
         for(int j=0;j<obj[0].length;j++){
            if(obj[0][j]==1){
                break;
            }else{
                arr[0][j] = 1;
            }
        }
        for(int i=1;i<obj.length;i++){
            for(int j=1;j<obj[0].length;j++){
                if(obj[i][j]==1){
                    arr[i][j] = 0;
                }else{
                    arr[i][j] = arr[i-1][j]+arr[i][j-1];
                }
            }
        }
        return arr[obj.length-1][obj[0].length-1];
    }
}

特殊点在于考虑到障碍物的位置 当障碍物在0行 0列时 后面的都不用考虑,当障碍无在中间某位置,到达这个位置的所有路径记为0

之前求的总数 我们这里可以讨论求最小路径的和

给定一个m*n的网格,网格用非负数填充,找到一条从左上角到右下角的最短路径。
注:每次只能向下或者向右移动。
子状态
从(0,0)-----(m-1,n-1)
F(i,j) 从(0,0)到达F(i,j)最短路径
状态递推
F(i,j) = min(F(i-1,j),F(i,j-1)+(i,j))
初始化
F(0,0) = (0,0)
特殊情况
F(0,i) - f(0,i-1)+(0,i)
F(i,0) =F(i-1)+(i,0)
返回结果
F(m-1,n-1)

public class Solution {
    public int minPathSum(int[][] grid) {
        if(grid==null){
            return 0;
        }
        int m = grid.length;
        int n = grid[0].length;
        int[][] arr = new int[m][n];
        arr[0][0] =grid[0][0];
         for(int i=1;i<=m-1;i++){
             arr[i][0] = grid[i][0]+arr[i-1][0];
         }
         for(int j=1;j<=n-1;j++){
             arr[0][j] = grid[0][j]+arr[0][j-1];
         }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                arr[i][j] = Math.min((arr[i-1][j]),(arr[i][j-1]))+grid[i][j];
           }
        }
        return arr[m-1][n-1];
    }
}

本题优秀的点在于 考虑最小路径动态规划

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值