DFS/BFS

本文介绍了深度优先搜索(DFS)和广度优先搜索(BFS)两种算法,并结合LeetCode题目展示了它们在图和树结构中的应用。DFS适用于一条路走到黑的情况,如遍历岛屿数量;BFS则常用于层次遍历,例如矩阵的01翻转问题。文章通过代码示例详细解释了这两种搜索策略,并提供了多源BFS的处理方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

695 岛屿的最大面积

 

DFS 深度优先,就是一条路走到黑。和stack(先进后出)一起使用。

深度优先搜索算法(英语:Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法。沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。

 

链接:https://leetcode-cn.com/tag/depth-first-search/

来源:力扣(LeetCode)

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

 

图的DFS中还需要有独立的DFS,比如统计岛屿个数,在每个岛屿中都需要用DFS,那么需要在DFS的外面再套一层for 循环

For r in range(xxxx)

Stack.append(root)

 

以图的DFS为例

 

如果图为空,则返回空值

if not root: return []

 

res = []

建立set来存储入栈的元素

Traversed = set()

判断题目是多个root还是单root,首先初始化栈,

stack = [root]

遍历stack中的元素,逐个处理

while stack:

取出栈顶元素

pop = stack.pop()

遍历栈顶元素的邻居,如果符合条件(index不越界,不在set中,且满足xx条件),则入栈,且在入栈后加入set

res.append(pop.val)

将当前元素周围符合条件的都加到stack中

if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][new_j] == '1':

                                stack.append((new_i, new_j))

                                #【特别注意】在放入队列以后,要马上标记成已经访问过,语义也是十分清楚的:反正只要进入了队列,你迟早都会遍历到它,而不是在出队列的时候再标记

                                #【特别注意】如果是出队列的时候再标记,会造成很多重复的结点进入队列,造成重复的操作,这句话如果你没有写对地方,代码会严重超时的

                                marked[new_i][new_j] = True

 

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

 

广度优先的主要应用场景 542 矩阵

 

思路:

对于 「Tree 的 BFS」 (典型的「单源 BFS」) 大家都已经轻车熟路了:

 

首先把 root 节点入队,再一层一层无脑遍历就行了。

对于 「图 的 BFS」 (「多源 BFS」) 做法其实也是一样滴~,与 「Tree 的 BFS」的区别注意以下两条就 ok 辣~

 

Tree 只有 1 个 root,而图可以有多个源点,所以首先需要把多个源点都入队;

Tree 是有向的因此不需要标识是否访问过,而对于无向图来说,必须得标志是否访问过哦!并且为了防止某个节点多次入队,需要在其入队之前就将其设置成已访问!

 

作者:sweetiee

链接:https://leetcode-cn.com/problems/01-matrix/solution/2chong-bfs-xiang-jie-dp-bi-xu-miao-dong-by-sweetie/

来源:力扣(LeetCode)

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

 

 

广度优先搜索,队列  多root

def BFS_solution1(root: Node):

if not root: return [], 0

遍历图

For r in range( rows ):

For c in range( cols ):

找到所有的root,加到queue中

layer = 0

queue = collection.deque([root])

while len(queue) != 0:

要实现层次遍历的时候才需要for ,注意此处,就算下面对queue进行了append操作(在for循环中),也不影响当前的len(queue)值,len(queue)只保存当前层次的节点个数。这也是能实现BFS的关键。

for i in range(len(queue)):

pop = queue.popleft() 取出队首元素

res[layer].append(pop.val) 将新元素加入队尾

if pop.left: queue.append(pop.left)

if pop.right: queue.append(pop.right)

遍历完一层才结束

layer += 1

res.append([])

 

return res[:-1], layer

做题总结:

第一步:画出树形图:

 

深度优先遍历

树上的每个节点:求解问题的不同阶段。叶子节点代表着当前子问题解决完成

状态变量

 

 

 

depth遍历到第几层,一般作为递归的终止条件:depth == len(input)2
path已经选了哪些数【1,3】
options当前阶段哪些数可以选(空间换时间)【2】

然后每一步都要记得状态回退

 

 

同时递归中path共用一个变量,在向result中添加数据的时候,需要浅拷贝path中的值

 

46.全排列


https://leetcode-cn.com/problems/permutations/

 

 

class Solution:

    def permute(self, nums: List[int]) -> List[List[int]]:

        def dfs(path, depth,options):    

            # 递归终止条件

            if depth == len(nums):

                # 注意此处要使用path[:]将数据浅拷贝一份

                res.append(path[:])

                return

            # 递归完成的时候,向path中添加新元素

            for i in range(len(nums)):

                # 如果该元素已经在path中,则跳过

                if not options[i]:

                    continue

                path.append(nums[i])

                options[i] = False

                dfs(path,depth+1, options)

                # 回退上一个步骤

                path.pop()

                options[i] = True

        res = []

        # 初始化,所有值都可选

        options = [True]*len(nums)

        dfs([],0,options)

        return res

22.括号生成


https://leetcode-cn.com/problems/generate-parentheses/

 

class Solution:

    def generateParenthesis(self, n: int-List[str]:

        # 回溯算法

        def dfs(num_left, num_right, path):

            # 递归终止条件

            if num_left == and num_right == n:

                # 注意此处path是string, python 中string是不可变变量,不需要浅拷贝

                res.append(path)

                return

            # 递归本体

            if num_left < n:

                dfs (num_left+1, num_right,path+'(')

            if num_left > num_right:

                dfs(num_left, num_right+1, path+')')

        res = []

        dfs(0,0,'')

        return res

93.复原IP地址


https://leetcode-cn.com/problems/restore-ip-addresses/

 

17.电话号码的字母组合


https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/

 

class Solution:

    def letterCombinations(self, digits: str-List[str]:

        result = ['']

        phoneMap = {

            "2""abc",

            "3""def",

            "4""ghi",

            "5""jkl",

            "6""mno",

            "7""pqrs",

            "8""tuv",

            "9""wxyz",

        }

        def dfs(path,i):

            # 递归终止

            if len(path) == len(digits):

                res.append(path[:])

                return

            for letter in phoneMap[digits[i]]:

                path += letter

                dfs(path,i+1)

                path = path[:-1]

        res = []

        if not digits:

            return []

        dfs('',0)

        return res

 

 

 

 

    #    """

    #     # 如何把stack 当作队列来用, 每次pop的时候,用pop(0)

    #     result = ['']

    #     phoneMap = {

    #         "2": "abc",

    #         "3": "def",

    #         "4": "ghi",

    #         "5": "jkl",

    #         "6": "mno",

    #         "7": "pqrs",

    #         "8": "tuv",

    #         "9": "wxyz",

    #     }

    #     if not digits:

    #         return []

 

    #     for d in digits:

    #         for i in range(len(result)):

    #             tmp = result.pop(0)

    #             #print(tmp)

    #             for letter in phoneMap[d]:

    #                 result.append(tmp + letter)

    #     return result

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值