刷题日志:Leetcode 62 63 Unique Paths系列(Python)

前言

Unique Paths在leetcode中有两道题,是动态规划比较经典的题型。本文将对这两道题的做法进行讲解。
在这里插入图片描述

62 Unique Paths

题目描述

A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).

How many possible unique paths are there?

即一个机器人站在一个m * n的矩阵的左上角,且每一步只能往下或往右走,问总共有多少条不同的路径可以到达右下角。

例子

Example 1:

Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Right -> Down
2. Right -> Down -> Right
3. Down -> Right -> Right

Example 2:

Input: m = 7, n = 3
Output: 28

思路

首先咱们从边缘开始分析。
原点因为是出发点,有且只有一种到达方式。
最左边的一列和最上面的一行,同理,由于不能往左/往上走,所以这些格点均只有一种到达方式。
现在我们分析坐标为(1, 1)的点,显而易见的有两条路可以到达,即先往右再往下或先往下再往右。
同理坐标(1, 2)的点,有3条路可以到达(下右右,右下右,右右下)。
这时我们换一种方式想,我们可以先到达(1, 1)的点,再往右走一步,或先到达(0, 2)的点,再往下走一步。有且只有这两种方式到达坐标(1, 2)的点。因此,到达(1, 2)的所有路径就是到达(0, 2)的所有路径加上到达(1, 1)的所有路径。依次类推,我们计算到右下角的最后一个点,并将其数值返回出来即可。
这就是动态规划的思想。

代码

class Solution(object):
    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        dp = [[1] * n for _ in range(m)]
        for i in range(1, m):
            for j in range(1, n):
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
        return dp[-1][-1]

63 Unique Paths II

题目描述

A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).

Now consider if some obstacles are added to the grids. How many unique paths would there be?

和上一题的要求基本一样,问机器人有多少种方法到达右下角。
不同的是,格子中有一些点是有障碍的,这些点机器人是不能通过的。

例子

Example 1:

Input:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
Output: 2
Explanation:
There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right

思路

这道题依然是和上一题一样的思路,动态规划,不同的是在开始循环每个点之前,我们要对一些障碍点进行处理。上一题中我们把所有的dp矩阵的点初始化成1(代表每个点初始时都是可以到达的),现在我们首先依然将这个dp矩阵初始化为1。
然后进行对所有格点遍历一次,如果有障碍物,则把dp矩阵的对应位置修改为0。
然后我们对第一行/第一列进行遍历,如果第一行和第一列中出现了障碍物,则把当前格点及其右边/下边的所有格点均设为0。这是因为如果第一行中的某个格点有障碍,那么它右边的所有点就一定都无法到达了。第一列同理。
最后,我们要考虑边界条件。如果起点或终点有障碍,那不用算了,肯定无法满足条件,直接返回0。
在做完以上所有处理后,我们按照第一题一样的写法来一次动态规划。注意一点就是我们只更新dp中不为0的点,即没有障碍物点。这个原因显而易见,就不多说了。上代码。

代码

class Solution(object):
    def uniquePathsWithObstacles(self, obstacleGrid):
        """
        :type obstacleGrid: List[List[int]]
        :rtype: int
        """
        m = len(obstacleGrid)
        n = len(obstacleGrid[0])

        dp = [[1] * n for _ in range(m)]
        # 处理障碍物的点
        for i in range(m):
            for j in range(n):
                if obstacleGrid[i][j] == 1:
                    dp[i][j] = 0
        # 处理起点终点            
        if dp[0][0] == 0 or dp[-1][-1] == 0:
            return 0
        # 处理第一行和第一列
        flag = 0
        for i in range(m):
            if flag == 1:
                dp[i][0] = 0
            elif dp[i][0] == 0:
                flag = 1
        flag = 0
        for i in range(n):
            if flag == 1:
                dp[0][i] = 0
            elif dp[0][i] == 0:
                flag = 1
        # 动态规划
        for i in range(1, m):
            for j in range(1, n):
                if dp[i][j] != 0:
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
        return dp[-1][-1]

总结

动态规划(dynamic programming)是刷题过程中必须掌握的一类题,在面试中也会经常遇到。希望大家可以通过这两道题对dp的概念有一个基本的认识。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值