DFS深度优先搜索算法

白昼怎懂夜的黑 提交于 2019-11-26 09:34:17

深度优先搜索算法(英语: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);
                恢复到打标记前的状态;//也就是说的{回溯一步}
            }
    }
}

 

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)将它从当前选取放进的排列中弹出。当前,在每一层的方法执行完毕,要返回的时候,都需要这么做。这两点可以简单概括为“状态重置”。

 

代码部分:

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

package Algorithm.DFS;

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

public class FullPermutationTest {


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

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

        //如果nums是空,生成空list并返回
        List<List<Integer>> res=new ArrayList<>();
        if(nums==null||nums.length==0){
            return res;
        }

        //used数组和len的定义
        int len=nums.length;
        boolean[] used=new boolean[len];
        makePermution(nums,used,0,len,new Stack<>(),res);
        return res;


    }

    public static void makePermution(int[] nums,boolean[] used,int curSize,
                                     int len,Stack<Integer> stack,List<List<Integer>> res){
            //根据格式,满足输出条件,输出解
            //此时stack已保存了nums中所有数字,成为了一个完整排列
            //成为完整排列,退出

            if(curSize==len){
            res.add(new ArrayList<>(stack));
            return;
        }else
        {
            for(int i=0;i<len;i++)
                if(!used[i])
                {
                    stack.push(nums[i]);
                    used[i]=true;
                    //往下一层进
                    makePermution(nums,used,curSize+1,len,stack,res);
                    //回溯,出栈和置标志位
                    stack.pop();
                    used[i]=false;
                }
        }

    }



    public static void main(String args[]){
        int[] nums={1,2,3};
        List<List<Integer>> result=permute(nums);
        for (int i=0;i<result.size();i++){
            System.out.println(result.get(i));
        }



    }
}

后续问题待更新。

 

参考资料:

作者:STZG  链接:https://blog.csdn.net/weixin_43272781/article/details/82959089 
作者:liweiwei1419 链接:https://leetcode-cn.com/problems/two-sum/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!