步骤:
画树分析
找到截止条件,遇到此条件就打印结果返回。
遍历候选节点,按条件筛选加入结果集。
递归dfs。
递归完重置下一轮的条件。
ABC全排列
6种输出
截止条件:结果集已经有这三种字符了
筛选条件:当前字符没加入结果集过
import java.util.ArrayList;
public class DFS {
public static void main(String[] args) {
char[] p = {'A', 'B', 'C'};
boolean[] pb = new boolean[]{false,false,false};
ArrayList<Character> list = new ArrayList<>();
dfs(p,pb,1, list);
}
public static void dfs(char[] p, boolean[] pb, int level, ArrayList<Character> res){
//1.截止条件
if(level==p.length+1){
System.out.println(res);
}
//2.遍历候选节点
for (int i = 0; i < p.length; i++) {
char c = p[i];
//2.1筛选
if(!pb[i]){
res.add(c);
pb[i] = true;
level++;
dfs(p,pb,level,res);//递归
pb[i] = false;//下一轮的初始条件
int index = res.indexOf(c);
res.remove(index);
level--;
}
}
}
}
进一步,level可以去掉,用res.size()来判断就可以了
import java.util.ArrayList;
public class DFS {
public static void main(String[] args) {
char[] p = {'A', 'B', 'C'};
boolean[] pb = new boolean[]{false,false,false};
ArrayList<Character> list = new ArrayList<>();
dfs(p,pb, list);
}
public static void dfs(char[] p, boolean[] pb, ArrayList<Character> res){
//1.截止条件
if(res.size()==p.length){
System.out.println(res);
}
//2.遍历候选节点
for (int i = 0; i < p.length; i++) {
char c = p[i];
//2.1筛选
if(!pb[i]){
res.add(c);
pb[i] = true;
dfs(p,pb,res);//递归
pb[i] = false;//下一轮的初始条件
int index = res.indexOf(c);
res.remove(index);
}
}
}
}
同样的,判断p[i]有没有被用过的pb[i]也可以去掉,通过修改char[] p再改回来来实现
import java.util.ArrayList;
public class DFS {
public static void main(String[] args) {
char[] p = {'A', 'B', 'C'};
boolean[] pb = new boolean[]{false,false,false};
ArrayList<Character> list = new ArrayList<>();
dfs(p, list);
}
public static void dfs(char[] p, ArrayList<Character> res){
//1.截止条件
if(res.size()==p.length){
System.out.println(res);
}
//2.遍历候选节点
for (int i = 0; i < p.length; i++) {
char c = p[i];
//2.1筛选
if(c!=' '){
res.add(c);
p[i] = ' ';
dfs(p,res);//递归
int index = res.indexOf(c);
res.remove(index);
p[i] = c;
}
}
}
}
合法ip地址
筛选条件:ip地址是0-255之间,可以是0但不能是0开头
截止:遍历到字符串最后一位,或者四个坑尾填充满了
import java.util.ArrayList;
public class IPDFS {
public static void main(String[] args) {
String str = "19216801";
ArrayList<String> res = new ArrayList<>();
ipdfs(str,0,0,res);
}
public static void ipdfs(String str, int index, int level, ArrayList<String> res){
//1.截止条件
if(level==4 || index==str.length()){
if(level==4 && index==str.length()){
System.out.println(res);
}
}
//2.遍历候选人,ip只能取1-3位
for (int i=1;i<4;i++){
if(index+i<=str.length()){
String s = str.substring(index,index+i);
//2.1筛选
if(Integer.parseInt(s)<256&&(s.equals("0")||!s.startsWith("0"))){
res.add(s);
ipdfs(str, index+i, level+1, res);
int in = res.indexOf(s);
res.remove(in);
}
}
}
}
}
leetcode 17 电话号码的字母组合
import java.util.ArrayList;
import java.util.List;
public class Solution {
static char[][] keyboard = {{},{},{'a','b','c'},{'d','e','f'},{'g','h','i'},{'j','k','l'},{'m','n','o'},{'p','q','r','s'},{'t','u','v'},{'w','x','y','z'}};
public List<String> letterCombinations(String digits) {
ArrayList<String> res = new ArrayList<>();
if(digits==null||digits.length()==0) return res;
dfs(digits,0,new StringBuilder(),res);
return res;
}
public static void dfs(String digits, int index, StringBuilder sb, ArrayList<String> res){
if(index==digits.length()){
res.add(sb.toString());
return;
}
for(char c: keyboard[digits.charAt(index)-'0']){
sb.append(c);
dfs(digits,index+1,sb,res);
sb.deleteCharAt(sb.length()-1);
}
}
}
leetcode 39 组合总数
class Solution {
public List<List<Integer>> combinationSum(int[] p, int t) {
List<List<Integer>> res = new ArrayList<>();
dfs(p, t, new ArrayList<Integer>(), res);
return res;
}
void dfs(int[] p, int t, List<Integer> list, List<List<Integer>> res){
//截止条件
int s = sum(list);
if(s>=t){
if(s==t){
List<Integer> temp = new ArrayList<>(list);
Collections.sort(temp);
if(!res.contains(temp)){
res.add(temp);
}
}
return;
}
for(int i=0;i<p.length;i++){
int c = p[i];
list.add(c);
dfs(p, t, list, res);
list.remove(list.size()-1);
}
}
int sum(List<Integer> list){
int res = 0;
for(int i: list){
res += i;
}
return res;
}
}
leetcode 46 全排列
同第一题
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
boolean[] flag = new boolean[nums.length];
dfs(nums, flag, new ArrayList<Integer>(), res);
return res;
}
void dfs(int[] nums, boolean[] flag, List<Integer> list, List<List<Integer>> res){
if(list.size()==nums.length){
res.add(new ArrayList<Integer>(list));
return;
}
for(int i=0;i<nums.length;i++){
if(!flag[i]){
list.add(nums[i]);
flag[i] = true;
dfs(nums, flag, list, res);
flag[i] = false;
list.remove(list.size()-1);
}
}
}
}
leetcode 47 全排列2
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
boolean[] flag = new boolean[nums.length];
dfs(nums, flag, new ArrayList<Integer>(), res);
return res;
}
void dfs(int[] nums, boolean[] flag, List<Integer> list, List<List<Integer>> res){
if(list.size()==nums.length){
List<Integer> temp = new ArrayList<Integer>(list);
if(!res.contains(temp)){
res.add(temp);
}
}
for(int i=0;i<nums.length;i++){
if(!flag[i]){
list.add(nums[i]);
flag[i] = true;
dfs(nums, flag, list, res);
flag[i] = false;
list.remove(list.size()-1);
}
}
}
}
leetcode 22 括号生成
简单写法:全排列生成所有括号对,再筛选出有效的括号输出
22 有效括号
class Solution {
public boolean isValid(String s) {
if(s==null||s.length()==0) return true;
Stack<Character> stack = new Stack<Character>();
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='('){
stack.push(')');
}else if(s.charAt(i)=='['){
stack.push(']');
}else if(s.charAt(i)=='{'){
stack.push('}');
}else if(stack.isEmpty()||stack.pop()!=s.charAt(i)){
return false;
}
}
return stack.isEmpty();
}
}
本题:
class Solution {
public List<String> generateParenthesis(int n) {
char[] p = new char[]{'(',')'};
List<String> res = new ArrayList<String>();
int[] count = new int[2];
dfs(n, new StringBuilder(), p, count, res);
return res;
}
void dfs(int n, StringBuilder sb, char[] p, int[] count, List<String> res){
p = new char[]{'(',')'};
if(sb.length()==n*2){
String str = sb.toString();
if(isTrue(str)){
res.add(str);
}
}
for(int i=0;i<2;i++){
if(count[i]<n){
sb.append(p[i]);
count[i]++;
dfs(n, sb, p, count, res);
count[i]--;
sb.deleteCharAt(sb.length()-1);
}
}
}
boolean isTrue(String s){
if(s==null||s.length()==0) return true;
Stack<Character> stack = new Stack<Character>();
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='('){
stack.push(')');
}else if(stack.isEmpty()||stack.pop()!=s.charAt(i)){
return false;
}
}
return stack.isEmpty();
}
}
树的DFS
leetcode 100 相同的树
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p==null&&q==null) return true;
if(p==null||q==null) return false;
return p.val==q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
leetcode 113 路径总和2
112 路径总和 递归写法
class Solution { public boolean hasPathSum(TreeNode root, int targetSum) { if(root==null) return false; if(root.left==null&&root.right==null) return root.val==targetSum; return hasPathSum(root.left, targetSum-root.val)||hasPathSum(root.right,targetSum-root.val); } }
本题:
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> res = new ArrayList<>();
if(root==null) return res;
List<Integer> list = new ArrayList<Integer>();
list.add(root.val);
targetSum -= root.val;
dfs(root, targetSum, list, res);
return res;
}
void dfs(TreeNode root, int targetSum, List<Integer> list, List<List<Integer>> res){
if(root.left==null&&root.right==null){
if(targetSum==0){
res.add(new ArrayList<Integer>(list));
}
return;
}
//筛选
if(root.left!=null){
list.add(root.left.val);
dfs(root.left, targetSum-root.left.val, list, res);
list.remove(list.size()-1);
}
if(root.right!=null){
list.add(root.right.val);
dfs(root.right, targetSum-root.right.val, list, res);
list.remove(list.size()-1);
}
}
}
leetcode 129 求根节点到叶节点数字之和
返回值是int,属于基本类型,不能直接int res = 0
带入,不然返回的肯定是0。
延续之前的解法,可以定义一个引用类型比如数组再带入。
class Solution {
public int sumNumbers(TreeNode root) {
int[] res = new int[1];
if(root==null) return 0;
if(root.left==null&&root.right==null) return root.val;
StringBuilder sb = new StringBuilder();
sb.append(root.val);
dfs(root, sb, res);
return res[0];
}
void dfs(TreeNode root, StringBuilder sb, int[] res){
if(root.left==null&&root.right==null){
res[0] += Integer.parseInt(sb.toString());
return;
}
if(root.left!=null){
sb.append(root.left.val);
dfs(root.left, sb, res);
sb.deleteCharAt(sb.length()-1);
}
if(root.right!=null){
sb.append(root.right.val);
dfs(root.right, sb, res);
sb.deleteCharAt(sb.length()-1);
}
}
}
也可以把res定义为全局变量
class Solution {
int res;
public int sumNumbers(TreeNode root) {
res = 0;
if(root.left==null&&root.right==null) return root.val;
StringBuilder sb = new StringBuilder();
sb.append(root.val);
dfs(root, sb);
return res;
}
void dfs(TreeNode root, StringBuilder sb){
if(root.left==null&&root.right==null){
res += Integer.parseInt(sb.toString());
return;
}
if(root.left!=null){
sb.append(root.left.val);
dfs(root.left, sb);
sb.deleteCharAt(sb.length()-1);
}
if(root.right!=null){
sb.append(root.right.val);
dfs(root.right, sb);
sb.deleteCharAt(sb.length()-1);
}
}
}
基于二维数组的dfs
leetcode 200 岛屿数量
先判断边界条件,定义一个res=0,遍历二维数组,如果当前是‘1’,就dfs并res++。
dfs中判断截止条件,然后将访问过的位置置为‘0’,再递归上下左右。
本题dfs完之后不用重置回来。
class Solution {
public int numIslands(char[][] p) {
if(p.length==0||p[0].length==0) return 0;
int res = 0;
for (int i = 0; i < p.length; i++) {
for (int j = 0; j < p[0].length; j++) {
if(p[i][j]=='1'){
dfs(p,i,j);
res++;
}
}
}
return res;
}
void dfs(char[][] p, int i, int j){
if(i<0||j<0||i>=p.length||j>=p[0].length||p[i][j]=='0'){
return;
}
p[i][j] = '0';
dfs(p, i-1, j);
dfs(p, i+1, j);
dfs(p, i, j-1);
dfs(p, i, j+1);
}
}
剑指offer 12 矩阵中的路径
class Solution {
boolean res;
public boolean exist(char[][] p, String s) {
res = false;
boolean[][] used = new boolean[p.length][p[0].length];
for (int i = 0; i < p.length; i++) {
for (int j = 0; j < p[0].length; j++) {
dfs(p, used, s, 0, i, j);
}
}
return res;
}
void dfs(char[][] p, boolean[][] used, String s, int index, int i, int j){
if(i<0||j<0||i>=p.length||j>=p[0].length||p[i][j]!=s.charAt(index)||used[i][j]||res){
return;
}
if(index==s.length()-1){
res = true;
return;
}
used[i][j] = true;
dfs(p, used, s, index+1, i+1, j);
dfs(p, used, s, index+1, i-1, j);
dfs(p, used, s, index+1, i, j+1);
dfs(p, used, s, index+1, i, j-1);
used[i][j] = false;
}
}