取法其上,得乎其中

再看深度优先算法

前言

这几天刷了很多道搜索的算法题,回头又看之前发的相关博文,简直解释的一蹋糊涂,我承认当时并没有完全掌握,东扯西扯哈哈哈。
其实深度优先算法(DFS)是一种思想,相对于广度优先搜索(BFS)而言,它的表现是,先进入最深层对象,然后回溯上来。脱离回溯这个词,实际上它与递归并没有什么区别,也就是更高级一些的暴力算法。所以没有必要把它想的太过于复杂,只是有一些抽象,有些难理解,在纸上推导几遍就清楚了。

概述

现有楼梯十层,小明可以走一步或两步,那么当走到第十层的时候一共有多少中走法?
这一题很简单,我们只需要在第一层的时候考虑,我有几种方法。很容易想到,两种,要么走一步,要么走两步,那我们就写两个递归就行了。出口是第十层,并且过滤掉大于10层的。

    public static void f(int step){
    if (step > 10) return;
    if (step == 10) {
        ans++;
    }
    f(step+1);
    f(step+2);
    
}

仔细思考,其实像这种递归也就是先进入更深层次,然后再慢慢的递归回来。那什么是DFS呢?回溯又是什么呢?
我们先更改一下上面的题目。

现有楼梯十层,小明可以走一步或两步,现在要求你输出这一路线过程,如: 1>2>3>4>5>6>7>8>9>10

如何编写?实际上我们可以通过函数参数的传递进行记录他的路线,但我要叙述的是DFS,先过滤掉这个想法。
先贴上解决这个问题的代码:

    public static void f(int step,List<Integer> l){
    if (step>10) return;
    if (step == 10) {
        for (int i = 0; i < l.size(); i++) {
            System.out.print(l.get(i) + "=>");
        }
        System.out.print("10");
        System.out.println();
    }else {
        l.add(step);
        f(step+1,l);
        f(step+2,l);
        l.remove(l.size()-1);
    }
    
}

我们没有走到目标楼层的情况下,对当前的list参数加入当前的层数,然后达到记录的目的。然后在当前层数中执行下一层的两种走法的函数。这点估计都能理解,那么为什么要最后删除list中最后一个元素呢? 可以着手测试,如果没有最后一句命令,到目标值的时候必然是一大段无意义的答案。


而使用这条命令呢?

这些便是正确答案。为什么? 如果不仔细思考,你肯定完全蒙圈了。我们这个时候画图分析一下。

如图所示,这便是回溯。相同的还可以使用这种思想解决数字全部排列问题(DFS排列)。最大的建议就是,用一张纸进行推到几遍,就明白了~

DFS排列数字

import java.util.ArrayList;

class Main {

static int[] vis = new int[9];

public static void main(String[] args) {

    f(0, new ArrayList<Integer>());

}

private static void f(int step, ArrayList<Integer> l) {
    // TODO Auto-generated method stub

    if (step == 9) {
        for (int i = 0; i < l.size(); i++) {
            System.out.print(l.get(i));
        }
        System.out.println();

    } else {

        for (int i = 0; i < 9; i++) {
            if (vis[i] == 0) {
                vis[i] = 1;
                l.add(i + 1);
                f(step + 1, l);
                vis[i] = 0;
                l.remove(l.size() - 1);
            }

        }

    }

}

}

DFS求集合所有子集

假设每一位数字有两种状态,一种是存在,一种是不存在。那么我们在递归的时候就可以求出所有的子集。


import java.util.*;

class Main{
    static int[] arr = {3, 4, 1, 2};
    public static void main(String[] args) {
        boolean[] vis = new boolean[4];
        f(0,vis);
    }

    static void f(int step, boolean[] vis) {
        if (step == arr.length) {
            List<Integer> list = new ArrayList<>();
            for (int i = 0; i < arr.length; i++) {
                if (vis[i]){
                    list.add(arr[i]);
                }
            }
            System.out.println(list);

        } else {
            vis[step] = false;
            f(step+1,vis);
            vis[step] = true;
            f(step+1,vis);
        }
    }

DFS求所有子序列

   public static void f(int index, List<Integer> list) {
        if (index > arr.length) {
            System.out.println(list);
        } else {
            for (int i = index; i <= arr.length; i++) {
                int temp = -1;
                if (i < arr.length) {
                    temp = arr[i];
                }
                list.add(temp);
                f(i + 1, list);
                list.remove(list.size() - 1);
            }

        }
    }
}






再看深度优先算法

https://ku-m.cn/index.php/archives/313/

作者

KuM

发布时间

2020-03-04

许可协议

CC BY 4.0

添加新评论