深度优先搜索算法(Depth First Search),简称DFS,是一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(n!)。
基本模板
int check(参数)
{
if(满足条件)
return 1;
return 0;
}
void dfs(int step)
{
判断边界
{
相应操作
}
尝试每一种可能
{
满足check条件
标记
继续下一步dfs(step+1)
恢复初始状态(回溯的时候要用到)
}
}
数的全排列问题
题目要求:给定一个数n,列出n的全排列。
分布解析:①从后往前排列:先排列后m (m 前n-m位数永远是有序的(从小到大升序)。 ②边界条件:设 m 表示倒数第 m 个数字即目前所在的数字位数,当 m>n 即 m=n+1时, 由于不存在第 m+1 个数字,此时排列结束,函数体执行完毕。 ③check条件:给第 i 个数一个标记值 flag ,当 flag 为 0 时表示改数字还未输出过, 当 flag 为1时表示该数字已经输出。 参考代码: 代码解析: 拓展练习: leetcode第200题 岛屿数量 难度:中等 问题描述:给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。 岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 此外,你可以假设该网格的四条边均被水包围。 示例1: 示例2: Hint: 参考代码: 复杂度分析: 时间复杂度:O(MN),其中 M 和 N 分别为行数和列数。 空间复杂度:O(MN),在最坏情况下,整个网格均为陆地,深度优先搜索的深度达到 MN。#include
我们以输入n=3为例,简要分析代码如何运行。
输入n=3,此时全局变量n被赋值,全局数组flag[]、vim[]均未赋值,即值为0;
执行代码: scanf("%d",&n);
变量值监控: n=3,
flag[]={0},
vim[]={0}.
执行函数dfs,此时为满足边界条件x==3,进入else语句的循环中;
执行代码: dfs(0);
int i;
变量值监控: n=3,
flag[]={0},
vim[]={0},
i.
i=1时,由于flag[1]=0,将1存入vim[0]等待输出,同时标记flag[1]表示1已经被存储;
执行代码: vim[0]=i;
flag[1]=1;
变量值监控: n=3,
flag[]={0,1,0,0,...},
vim[]={1,0,0,...},
i=1.
继续排列面第二个数字,此时x=1也未满足边界条件,进入循环,i=1时,由于flag[1]=1即1已经被存储,
从而继续循环i++,i=2时flag[2]=0即未被存储,重复上述存储1时的步骤;
执行代码: i++;
vim[1]=2;
flag[2]=1;
变量值监控: n=3,
flag[]={0,1,1,0,...},
vim[]={1,2,0,...},
i=2.
进入第三重循环,与前两者类似,存入数字3,继续执行 dfs(x+1),但由于此时x=2+1=3满足边界条件,不再进行 存储,我们从vim[0]开始输出,得到第一个排列:1 2 3;
执行代码: i++;
vim[2]=3;
flag[3]=1;
if(x==n) {
int j;
for(j=0;j<n;j++) printf("%d ",vim[j]);
printf("\n");
}
变量值监控: n=3,
flag[]={0,1,1,1,...},
vim[]={1,2,3,...},
i=3.
输出流: 1 2 3
此时我们将flag[3]的值回调为0,回到第二个循环,将flag[2]的值回调为[0],执行循环i++,此时i=3,将3存 入vim[1],同时标记flag[3]=1,继续进入 dfs(3),由于此时flag[1]=1,即1已被存储,执行循环,将2存入 vim[2]同时标记flag[2]=1,达到边界条件,进行第二组输出,得到排列:1 3 2;
执行代码: flag[3]=0;
flag[2]=0
vim[1]=3;
flag[3]=1;
dfs(3):
flag[2]=1;
vim[2]=2;
if(x==n) {
int j;
for(j=0;j<n;j++) printf("%d ",vim[j]);
printf("\n");
}
变量值监控: n=3,
flag[]={0,1,1,1,...},
vim[]={1,3,2,...},
i=3.
输出流: 1 3 2
此时我们已经基本明白函数执行的思路,即从最后一个数字开始不断往前进行递推,保持前k个数字的有序性,对后面 的n-k个数进行全排列,通过循环输出不同序列,在循环中通过vim存储要输出的数字,通过flag标记某个数字是否 已经完成存储。接下来返回第一个循环,即初始化flag[1]的值为[0],执行i++循环,存入2作为vim[0],得到序 列:2 1 3 , 2 3 1 ,重复上述步骤,得到3作为vim[0]的两个序列:3 1 2 ,3 2 1.
输出结果: 1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
输入:grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
输出:1
输入:grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出:3
m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j]
的值为 '0'
或 '1'
class Solution {
private:
void dfs(vector