1、问题描述
问题:一个机器人位于一个 m * n 网格的左上角 (起始点在下图中标记为“开始” ),机器人每次只能向下或者向右移动一步,现在机器人试图达到网格的右下角(在下图中标记为“结束”)。问总共有多少条不同的路径?

-
- 示例:
-
- 输入:m = 3, n = 2
- 输出: 3
- 解释: 从左上角开始,总共有 3 条路径可以到达右下角:
- 1. 向右 -> 向右 -> 向下
- 2. 向右 -> 向下 -> 向右
- 3. 向下 -> 向右 -> 向右
2、算法分析
1)备忘录
dp[i][j]表示到i行j列的格子的路径数;
2)初始化状态
因为每次只能向下或者向右进行移动,所以第一行第一列的所有路径数都是1;其他格子路劲数初始化为0;
3)状态参数
状态参数就是i行j列;
4)决策
因为只能向下或者向右移动,因此d[i][j] = d[i-1][j] + d[i][j-1]
3、状态转移方程

4、算法实现
- package main
-
- import "fmt"
-
-
- func DP(m int, n int) int {
- // 创建备忘录
- dp := make([][]int, m)
- for i := range dp{
- dp[i] = make([]int, n)
- }
-
- // 初始化状态
- for i := 0; i < m; i++ {
- dp[i][0] = 1
- }
- for i := 0; i < n; i++ {
- dp[0][i] = 1
- }
-
- // 转移方程转换实现
- for i := 0; i< m; i++ {
- for j := 0; j < n; j++ {
- if i == 0 || j == 0 {
- dp[i][j] = 1
- } else {
- dp[i][j] = dp[i-1][j] + dp[i][j-1]
- }
- }
- }
- return dp[m-1][n-1] // 输出答案
- }
-
- func main() {
- m := 3
- n := 7
- fmt.Println(DP(m, n)) // 输出答案
- }
1、问题描述
问题:一个机器人位于一个 m * n 网格的左上角 (起始点在下图中标记为“开始” )。机器人每次只能向下或者向右移动一步,现在机器人试图达到网格的右下角(在下图中标记为“结束”)。考虑网格中有障碍物,网格中的障碍物和空位置分别用 1 和 0 来表示,那么从左上角到右下角将会有多少条不同的路径?

-
- 示例:
-
- 输入:
- [
- [0, 0, 0],
- [0, 1, 0],
- [0, 0, 0]
- ]
- 输出: 2
- 解释:3 * 3 网格的正中间有一个障碍物。
- 从左上角到右下角一共有 2 条不同的路径:
- 1. 向右 -> 向右 -> 向下 -> 向下
- 2. 向下 -> 向下 -> 向右 -> 向右
2、算法分析
1)备忘录
dp[i][j]表示到i行j列的格子的路径数;
2)初始化状态
依然先考虑网格的第一行和第一列,第一行永远只能从左侧的格子往前走;第一列永远只能从上方的格子往下走。由于我们只能向右或向下走,所以第一行和第一列的格子永远只能存在 1 条路径。但是,我们还需要再考虑那些有障碍的格子,对这些格子来说,它们的路径总数应该是 0 而不是 1。
3)状态参数
状态参数就是i行j列; 状态参数依然是格子的行数和列数;
4)决策
因为只能向下或者向右移动,因此d[i][j] = d[i-1][j] + d[i][j-1] ;有障碍物的格子的路径数为0;
3、状态转移方程
4、算法实现
- package main
-
- import "fmt"
-
-
- func DP(m int, n int, array [][]int) int {
- // 创建备忘录
- dp := make([][]int, m)
- for i := range dp{
- dp[i] = make([]int, n)
- }
-
- // 初始化状态
- for i := 0; i < m; i++ {
- if array[i][0] == 1 {
- dp[i][0] = 0
- } else {
- dp[i][0] = 1
- }
- }
- for i := 0; i < n; i++ {
- if array[0][i] == 1 {
- dp[0][i] = 0
- } else {
- dp[0][i] = 1
- }
- }
-
- // 转移方程转换实现
- for i := 0; i< m; i++ {
- for j := 0; j < n; j++ {
- if (i == 0 || j == 0) && array[i][j] == 0 {
- dp[i][j] = 1
- } else if array[i][j] == 1 {
- dp[i][j] = 0
- } else {
- dp[i][j] = dp[i-1][j] + dp[i][j-1]
- }
- }
- }
- return dp[m-1][n-1] // 输出答案
- }
-
- func main() {
- m := 3
- n := 3
- array := [][]int{{0, 0, 0},
- {0, 1, 0},
- {0, 0, 0}}
- fmt.Println(DP(m, n, array)) // 输出答案
- }
1、问题描述
题目:给出一个非负整数数组 A,你最初定位在数组的第一个位置。数组中的每个元素代表你在那个位置可以跳跃的最大长度。判断你是否能到达数组的最后一个位置。
-
- 示例1:
-
- 输入:A = [2, 3, 1, 1, 6]
- 输出: True
- 解释: 我们可以先跳 1 步,从位置 0 到达位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
2、算法分析
1)备忘录
DP[i] 来表示能否从出发点到达位置 i。
2)初始化状态
初始化状态就是 0 这个位置。因为这个位置是出发点,因此肯定可以到达,所以我们可以将其初始化成 True。
3)状态参数
状态参数也比较容易看出,只有数组的位置是变化的,因此状态参数就是当前位置 i
4)决策
要知道能否到达位置 i,就需要逐个看前面的位置,判定能否从位置 i−1、i−2、i−3 … 跳到位置 i 上。
3、状态转移方程
4、算法实现
- package main
-
- import "fmt"
-
-
- func DP(array []int) bool {
- length := len(array)
- // 创建备忘录
- dp := make([]bool, length)
-
- // 初始化状态
- for i := 0; i < length; i++ {
- dp[i] = false
- }
- dp[0] = true
-
- // 转移方程转换实现
- for i := 1; i< length; i++ {
- for j := 0; j < i; j++ {
- if dp[j] && j + array[j] >= i {
- dp[i] = true
- break
- }
- }
- }
- return dp[length-1] // 输出答案
- }
-
- func main() {
- array := []int{2, 3, 1, 1, 6}
- fmt.Println(DP(array)) // 输出答案
- }
声明:本文参考极客时间《动态规划面试宝典》