深度优先算法
Posted 碎屑笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度优先算法相关的知识,希望对你有一定的参考价值。
深度优先算法(Depth-First-Search)
深度优先算法简称为DFS,最直接的例子就是“走迷宫”,首先沿着其中的一个路口一直走,当走不通时,就返回上一个岔路口,沿着另一条路径一直走,知道走到出口为止。
深度优先算法的说明以无向图为例,进行说明
以连接表的方式来存储图
private int v; //顶点的个数
private LinkedList<Integer> adj[]; //邻接表
public Graph(int v){
this.v = v;
adj = new LinkedList[v];
for(int i=0; i<v; i++){
adj[i] = new LinkedList<Integer>();
}
}
public void addEdge(int s, int t){ //无向图一条边存两次
adj[s].add(t);
adj[t].add(s);
}
public void showGraph(){
for(int i=0; i<v; i++){
Iterator iterator = adj[i].iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
存储的样式如图所示,最左边的标识顶点,右边的表示与该顶点相连的节点
通过深度优先对图进行查找
/*
* visited用来记录已经被访问的顶点,用来避免顶点被重复访问
* prev 用来记录搜索路径,
*
* */
boolean found = false; //found为false表示还没有找到
//在一张图中从s点开始,去查找t
public void dfs(int s, int t){
found = false;
boolean[] visited = new boolean[v];
int[] prev = new int[v];
for (int i=0; i< v; i++){
prev[i] = -1;
}
}
private void recurDfs(int w, int t, boolean[] visited, int[] prev){
if(found == true){ return ;} //判断是否已经找到
visited[w] = true; //找过的节点为true
if(w==t){ //找到了使found为true
found = true;
return ;
}
for(int i=0; i< adj[w].size(); i++){
int q = adj[w].get(i);
if(!visited[q]){ //没有访问过的节点
prev[q] = w;
recurDfs(q,t,visited,prev);
}
}
}
LeetCode练习
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
链接:https://leetcode-cn.com/problems/generate-parentheses
示例:
输入:n = 3
输出:[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
暴力法
可以生成长度为2n的所有可能的字符序列,然后我们检查每一个是否满足条件。
为了检测字符串是否有效,我们需要对字符串进行遍历,只有当其中的 '(' 数等于 ‘)’数时才表示该字符序列有效。
public List<String> generateParenthesis(int n) {
List<String> combinations = new ArrayList(); //combinations用来存储满足条件的结果
generateAll(new char[2 * n], 0, combinations);
return combinations;
}
//通过遍历将数组的所有可能都填写进去,当pos的长度等于current.length时,对此时的数组进行判断,如果该数组满足条件,则将其添加到result中
public void generateAll(char[] current, int pos, List<String> result) {
if (pos == current.length) { //
if (valid(current)) { //递归的终止条件,当该数组满足条件时,将其加入到result中
result.add(new String(current));
}
} else {
current[pos] = '('; //递归添加各种可能的数据,并在其长度等于2*n时对数组进行判断
generateAll(current, pos+1, result);
current[pos] = ')';
generateAll(current, pos+1, result);
}
}
public boolean valid(char[] current) {
int balance = 0;
for (char c: current) { //对current数组进行遍历
if (c == '(') {balance++;}
else {balance--;}
if (balance < 0) {return false;}
}
return (balance == 0); //左括号和右括号的数量一致
}
使用深度优先算法(回溯法)来实现
如果左括号数量不大于 n,我们可以放一个左括号。如果右括号数量小于左括号的数量,我们可以放一个右括号。
public List<String> generateParenthesis(int n) {
List<String> ans = new ArrayList();
backtrack(ans, new StringBuilder(), 0, 0, n);
return ans;
}
public void backtrack(List<String> ans, StringBuilder cur, int open, int close, int max){
//ans用于存储满足条件的结果
if (cur.length() == max * 2) {
ans.add(cur.toString());
return;
}
if (open < max) {//open表示左括号位置的下标 open左括号数小于n,可以添加左括号
cur.append('(');
backtrack(ans, cur, open+1, close, max); //open = 0, close = 0 , max = 1
cur.deleteCharAt(cur.length() - 1);
}
if (close < open) {//close表示右括号 右括号数小于左括号数
cur.append(')');
backtrack(ans, cur, open, close+1, max);
cur.deleteCharAt(cur.length() - 1);
}
}
以上是关于深度优先算法的主要内容,如果未能解决你的问题,请参考以下文章