zoukankan      html  css  js  c++  java
  • 【Leetcode 动态规划、深度优先搜索】不同路径(62)、 不同路径 II(63)、不同路径 III(980)

    题目:不同路径 II(63)

    一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

    机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

    现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

    网格中的障碍物和空位置分别用 1 和 0 来表示。

    说明:m 和 n 的值均不超过 100。

    示例 1:

    输入:
    [
      [0,0,0],
      [0,1,0],
      [0,0,0]
    ]
    输出: 2
    解释:
    3x3 网格的正中间有一个障碍物。
    从左上角到右下角一共有 2 条不同的路径:
    1. 向右 -> 向右 -> 向下 -> 向下
    2. 向下 -> 向下 -> 向右 -> 向右
    

    解答

    
    # 动态规划转换方程:
    # ① dp[i][j] = dp[i-1][j] + dp[i][j-1]  (i>0 and j>0)
    # ② dp[i][j] = 1    ((i=0 and dp[i][j-1]!=0) or (j=0 and dp[i-1][j]!=0)), 处理边界, 要求到(i,j)前一个位置路径数不是0, 否则就代表这条路被阻断了
    # dp[i][j]表示能到(i, j)位置的路径条数. 条件②的dp[i][j-1]!=0、dp[i-1][j]!=0是必须的,否则有反例:[[0, 0], [1, 1], [0, 0]]
    
    class Solution:
        # 二维dp
        def uniquePathsWithObstacles(self, nums):
            if not nums or nums[0][0] == 1:
                return 0
            rows = len(nums)
            cols = len(nums[0])
            dp = [[0 for _ in range(cols)] for _ in range(rows)]
    
            for i in range(rows):
                for j in range(cols):
                    if i == 0 and j == 0:  # 处理左上角
                        dp[i][j] = 1
                        continue
                    if nums[i][j] == 1:  # 障碍物
                        dp[i][j] = 0
                        continue
    
                    if (j == 0 and dp[i-1][j] != 0) or (i == 0 and dp[i][j-1] != 0):  # 处理左、上边界
                        dp[i][j] = 1
                    else:
                        dp[i][j] = dp[i-1][j] + dp[i][j-1]
            return dp[-1][-1]
    
    
    
    # # 深搜超时,暴风哭泣辽。。
    # class Solution:
    #     def __init__(self):
    #         self.rows = 0
    #         self.cols = 0
    #         self.book = [[]]
    #         self.nums = [[]]
    #         self.cnt = 0
    #         self.next = [
    #             [0, 1],
    #             [1, 0]
    #         ]
    #
    #     def uniquePathsWithObstacles(self, obstacleGrid):
    #         if not obstacleGrid:
    #             return 0
    #         self.nums = obstacleGrid
    #         self.rows = len(obstacleGrid)
    #         self.cols = len(obstacleGrid[0])
    #
    #         self.book = [[0 for _ in range(self.cols)] for _ in range(self.rows)]
    #         self.book[0][0] = 1
    #         self.dfs(0, 0)
    #         return self.cnt
    #
    #     def dfs(self, x, y):
    #         if x == self.rows-1 and y == self.cols-1:
    #             self.cnt += 1
    #             return
    #         for i in range(2):
    #             tx = x + self.next[i][0]
    #             ty = y + self.next[i][1]
    #             if 0 <= tx < self.rows and 0 <= ty < self.cols and self.book[tx][ty] == 0 and self.nums[tx][ty] == 0:
    #                 self.book[tx][ty] = 1
    #                 self.dfs(tx, ty)
    #                 self.book[tx][ty] = 0
    
    

    题目:不同路径(62)https://leetcode-cn.com/problems/unique-paths/

    不存在障碍物,很简单,动态规划嗖嗖的

    # 动态规划转换方程:
    # ① dp[i][j] = dp[i-1][j] + dp[i][j-1]  (i>0 and j>0)
    # ② dp[i][j] = 1    (i=0 or j=0), 处理边界
    # dp[i][j]表示能到(i, j)位置的路径条数
    
    class Solution:
        # 二维dp
        def uniquePaths(self, rows, cols):
            if rows == cols == 0:
                return 0
            dp = [[0 for _ in range(cols)] for _ in range(rows)]
    
            for i in range(rows):
                for j in range(cols):
                    if i == 0 and j == 0:  # 处理左上角
                        dp[i][j] = 1
                        continue
                    if i == 0 or j == 0:  # 处理边界
                        dp[i][j] = 1
                    else:
                        dp[i][j] = dp[i-1][j] + dp[i][j-1]
            return dp[-1][-1]
    
    
    # 深度优先搜索也OK,不写了,参考不同路径II
    

    题目:不同路径 III(980)https://leetcode-cn.com/problems/unique-paths-iii/

    可以移动方向改为上、下、左、右了。还有一点要特别注意:每一个无障碍方格都要通过一次
    深搜代码如下:

    # 深度优先搜索
    class Solution:
        def __init__(self):
            self.rows = 0
            self.cols = 0
            self.book = [[]]
            self.nums = [[]]
            self.cnt = 0
            self.req_step = 0  # 要求每条路径的步数 = 无障碍方格数
            self.next = [
                [0, 1],
                [1, 0],
                [0, -1],
                [-1, 0]
            ]
    
        def uniquePathsIII(self, obstacleGrid):
            if not obstacleGrid or obstacleGrid[0][0] == -1:
                return 0
            self.nums = obstacleGrid
            self.rows = len(obstacleGrid)
            self.cols = len(obstacleGrid[0])
    
            self.book = [[0 for _ in range(self.cols)] for _ in range(self.rows)]
            for i in range(self.rows):
                for j in range(self.cols):
                    if self.nums[i][j] == 1:  # 起点
                        start_x = i
                        start_y = j
                    if self.nums[i][j] != -1:  # 统计一共要走多少步
                        self.req_step += 1
            self.book[start_x][start_y] = 1
            self.dfs(start_x, start_y, 1)
            return self.cnt
    
        def dfs(self, x, y, step):
            if self.nums[x][y] == 2 and step == self.req_step:  # 到达终点,并且每一个无障碍方格都通过一次
                self.cnt += 1
                return
            for i in range(4):
                tx = x + self.next[i][0]
                ty = y + self.next[i][1]
                if 0 <= tx < self.rows and 0 <= ty < self.cols and self.book[tx][ty] == 0 and self.nums[tx][ty] != -1:
                    self.book[tx][ty] = 1
                    self.dfs(tx, ty, step+1)
                    self.book[tx][ty] = 0
    

    相似题目

    剑指 Offer 47. 礼物的最大价值

  • 相关阅读:
    Jmeter调试工具---Debug Sampler
    jmeter --- 搭建持续集成接口测试平台(Jenkins+Ant+Jmeter)
    Jmeter --- 组件执行顺序与作用域
    第五讲.字典,集合,数组排序(快速排序,冒泡,默认排序)(源代码)
    第五讲.字典,集合,数组排序(快速排序,冒泡,默认排序)
    第六讲 Block块语法及Block与数组的排序,ios字面量的使用(源代码上传)
    第六讲 Block块语法及Block与数组的排序,ios字面量的使用
    jQuery FileUpload等插件的使用实例
    文件上传(js, C#)
    Excel导出的几种方式
  • 原文地址:https://www.cnblogs.com/ldy-miss/p/13255255.html
Copyright © 2011-2022 走看看