DFS深度优先搜索算法

本文介绍了深度优先搜索(DFS)算法,包括基本概念、模板和应用实例,如全排列问题、路径总和II和二叉树的所有路径。通过DFS与回溯相结合,解决了多种编程问题,同时对比了层序遍历的应用。
摘要由CSDN通过智能技术生成

深度优先搜索算法(英语:Depth-First-Search,简称DFS)

是一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。(Wiki)

(直到走不下去才往回走)

基本模板

int search(int t)
{
    if(满足输出条件)
    {
        输出解;
    }
    else
    {
        for(int i=1;i<=尝试方法数;i++)
            if(满足进一步搜索条件)
            {
                为进一步搜索所需要的状态打上标记;
                search(t+1);
                恢复到打标记前的状态;//也就是说的{回溯一步}
            }
    }
}

第一部分 DFS+回溯

1.全排列问题(leetcode.46):

给定一个没有重复数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:
[[1,2,3],[1,3,2], [2,1,3], [2,3,1],[3,1,2],[3,2,1]]

 

思路分析

这是一个非常典型的使用 回溯算法 解决的问题。解决回溯问题,一定不要偷懒,拿起纸和笔,画出一个树形结构,思路和代码就会比较清晰了

方法:回溯算法(深度优先遍历+状态重置)

以示例 [1,2,3] 为例,因为是排列问题,我们只要按顺序选取数字,保证上一层选过的数字不在下一层出现,就能够得到不重不漏的所有排列方法,画出树形结构如下图:

46-1.png

 

注意:

1、在每一层,我们都有若干条分支供我们选择。由于是排列问题,之前使用过的数字,在下一层中不能再选取,那么从当前层走到下一层的时候,我们就要问一问自己,哪些数字已经使用过。在编码实现中,可以使用一个布尔型数组 used,用于记录之前(当前路径之前的层)哪些数字使用过。

2、在程序执行到上面这棵树的叶子结点的时候,此时递归到底,方法要返回了,对于这个最后一层选取的数,要做两件事情:(1)释放对它的占用;(2)将它从当前选取放进的排列中弹出。当前,在每一层的方法执行完毕,要返回的时候,都需要这么做。这两点可以简单概括为“状态重置”。

 

代码部分:

代码力求清晰准确,里边的每一步都可以对应基本模板填写。

1.使用stack

package Algorithm.DFS;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

    //从叶子节点到根节点形成的一条路径,就是题目要求的一个排列;
    //在更深层可选的数一定不能包括在之前层选过的数,所以需要使用一个数组used记录哪些数在之前层选过
    //DFS的核心理解是在每一个分叉位置都是一个新i了,所以每一层i是独立的,回溯的时候意味着一个分支走完了
    //所以回到分叉位的时候状态要重置

public class FullPermutationTest {

   //深度优先遍历
    //代码分为两部分 1.声明 2.递归
    //声明部分需要声明一个result结果集,一个boolean数组存放状态,
    //一个len确认状态数组的长度

    public static List<List<Integer>> permute(int[] nums){

        List<List<Integer>>  result=new ArrayList<>();
        if(nums==null||nums.length==0){
            return result;
        }
        int len=nums.length;

        boolean[] used=new boolean[len];
        makePermution(nums,used,0,new Stack<Integer>(),result);
        return result;

        }

    //终止条件为当前size=数组长度,这时候往result里增加当前stack的值,成为result的一个子集
    //递归条件是如果当前位没有用到,塞进stack,然后置用过状态
    //然后进一步递归,传cursize+1。递归的主要递归点是cursize,终止条件也是cursize
    //回溯 stackpop,used状态回溯,没什么好说的

        public static void makePermution(int[] nums,boolean[] used,
                                         int curSize,Stack<Integer> stack,
                                         List<List<Integer>> result){
            if(curSize==nums.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值