路漫漫其修远兮
吾将上下而求索

算法学习:bfs+dfs

概念

深度优先搜索算法(Depth-First-Search),是搜索算法的一种。它沿着树的深度遍历树的节点,尽可能深的搜索树的分 支。堆栈实现,递归实现

广度优先搜索算法(Breadth-First-Search),是一种图形搜索算法,从根节点开始,沿着树(图)的宽度遍历树(图)的节点。队列实现

机器人的运动范围

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

示例 1:

输入:m = 2, n = 3, k = 1
输出:3
示例 2:

输入:m = 3, n = 1, k = 0
输出:1
提示:

1 <= n,m <= 100
0 <= k <= 20

======================================

1. 如何计算行坐标和列坐标的数位之和

对于一个整数 n,我们有以下伪代码模板:

int sum = 0;
    while (n > 0){
        sum += n % 10; // n对10取余
        n /= 10;       // n等于整除10之后的值
    }
    return sum;

因此我们只需将行坐标和列坐标分别求数位之和,将其结果相加即可。

2. 哪些格子在运动范围之内

机器人的运动范围需要同时满足以下两个条件:

  • 当前格子坐标数位之和不大于 k;

  • 从坐标 (0, 0) 通过上下左右移动可以到达当前格子

20200708-8502117633.png

对于上面的矩阵 m = 4, n = 12, k = 2,蓝色区域是满足条件的格子,所以返回结果为 6。需要注意的是,黄色区域虽然满足数位之和不大于 k,但是由于不满足第二个条件,即无法从 (0, 0) 位置移动过去,故不计算在结果之内。

我们可以将矩阵看作一个有向图,而遍历图的方式一般分为广度优先搜索(BFS)和深度优先搜索(DFS),因此从 (0, 0) 点出发,采用 BFS 或 DFS ,如果当前格子满足以上两个条件,则将结果加 1。

方法一:广度优先搜索 BFS

广度优先搜索一般使用队列来实现。我们先将 (0, 0)加入队列,当队列不为空时,每次将队首坐标出队,加入到集合中,再将满足以上两个条件的坐标加入到队尾,直到队列为空。

20200708-6291664201.gif

代码

非常感谢 @tike5 对 BFS 和 DFS 代码提出的优化方法:

在广度优先算法,由于可行解的连通性和结构,仅考虑向下和向右的移动方向即可,深度优先算法同样如此。

由于题目要求从 (0, 0) 点出发,因此任何一个点都可以只通过向右和向下两个动作达到,因此代码中可以只考虑这两个方向。

class Solution:
    def sum_rc(self,row,col):
        tmp = 0
        while row > 0:
            tmp += row % 10
            row //= 10
        while col > 0:
            tmp += col % 10
            col //= 10
        return tmp

    def movingCount(self, m: int, n: int, k: int) -> int:
        marked = set()  # 将访问过的点添加到集合marked中,从(0,0)开始
        queue = collections.deque()
        queue.append((0,0))
        while queue:
            x, y = queue.popleft()
            if (x,y) not in marked and self.sum_rc(x,y) <= k:
                marked.add((x,y)) 
                for dx, dy in [(1,0),(0,1)]:  # 仅考虑向右和向下即可
                    if 0 <= x + dx < m and 0 <= y + dy < n:
                        queue.append((x+dx,y+dy)) 
        return len(marked)

复杂度分析

  • 时间复杂度:O(m×n)。

  • 空间复杂度:O(m×n)。

方法二:深度优先搜索 DFS

深度优先搜索一般使用栈来实现。本题使用递归可以更轻松实现,我们定义一个递归函数 dfs(),如果坐标不满足条件,结束递归状态,否则将下一步满足条件的坐标代入递归函数。

class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:
        def sumofDigit(x, y):
            result = 0
            while x > 0:
                result += x % 10
                x //= 10
            while y > 0:
                result += y % 10
                y //= 10
            return result
        
        def dfs(i, j):
            if i == m or j == n or sumofDigit(i, j) > k or (i, j) in marked:
                return 
            marked.add((i, j))
            dfs(i + 1, j)
            dfs(i, j + 1)
            
        marked = set()
        dfs(0, 0)
        return len(marked)

感谢 @ZacBi 对代码可读性提出的建议 🙂

复杂度分析

  • 时间复杂度:O(m×n)。

  • 空间复杂度:O(m×n)。

作者:z1m

链接:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/solution/bfs-by-z1m/

来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

未经允许不得转载:江哥架构师笔记 » 算法学习:bfs+dfs

分享到:更多 ()

评论 抢沙发

评论前必须登录!