dfs 深度优先搜索算法,用于深度遍历查找所需的结果。
时间复杂度:一般根据特定情况分析
空间复杂度:O(n),递归时栈空间的代价为 O(n),n为数据长度,递归多少层;
一般的dfs模板如下:
public void dfs(int[] candidates, int target,int index, List<Integer> res) {
// 终止递归的条件
if (target == 0) {
ans.add(new ArrayList(res));
return;
}
//
for (int i = index; i < candidates.length; i++) {
if (target - candidates[i] >= 0) { // 根据题意 剪枝条件,此处只是举例
res.add(candidates[i]);
dfs(candidates, target - candidates[i],i, res);
// 需要删除最后一个叶子节点的结果,返回上一层在遍历其他的结果
res.remove(res.size() - 1);
}
}
}
下面的题目基本都是根据该dfs模板实现对应的方法,差异只是题意需求的区别,整体模块框架一致。
但是需要了解每一行的意义,有时候参数差一个,区别都很大。仅此记笔记进行查遗补漏。
class Solution {
List<String> res = new ArrayList<>();
String[] letters = {"", "*", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
public List<String> letterCombinations(String digits) {
if(digits.length() == 0){
return new ArrayList<>();
}
findCombinations(digits, 0, "");
return res;
}
public void findCombinations(String digits, int index, String ans) {
// 终止条件
if (index == digits.length()) {
res.add(ans);
return;
}
char ch = digits.charAt(index);
int k = ch - '0';
String letter = letters[k];
for (int j = 0; j < letter.length(); j++) {
findCombinations(digits, index + 1, ans + letter.charAt(j));
}
}
}
class Solution {
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
if (n < 1) return new ArrayList<>();
dfs(n, 0, 0, new StringBuilder());
return res;
}
/**
* @param n
* @param left 左括号数量
* @param right 右括号数量
* @param str
*/
public void dfs(int n, int left, int right, StringBuilder str) {
if (left == n && right == n) {
res.add(str.toString());
return;
}
if (left < n) {
dfs(n, left + 1, right, str.append("("));
str.deleteCharAt(str.length() - 1);
}
if (left > right) {
dfs(n, left, right + 1, str.append(")"));
str.deleteCharAt(str.length() - 1);
}
}
}
class Solution {
List<List<Integer>> ans = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<Integer> list = new ArrayList<>();
dfs(candidates, target,0, list);
return ans;
}
/**
*
* @param candidates
* @param target
* @param index index目的是控制二叉数中同一层,不能使用前面用过的元素
* @param res
*/
public void dfs(int[] candidates, int target,int index, List<Integer> res) {
if (target == 0) {
ans.add(new ArrayList(res));
return;
}
for (int i = index; i < candidates.length; i++) {
if (target - candidates[i] >= 0) {
res.add(candidates[i]);
dfs(candidates, target - candidates[i],i, res);
res.remove(res.size() - 1);
}
}
}
}
class Solution {
List<List<Integer>> ans = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
List<Integer> list = new ArrayList<>();
dfs(nums, 0, list);
return ans;
}
public void dfs(int[] nums, int index, List<Integer> res) {
if (nums.length == res.size()) {
ans.add(new ArrayList<>(res));
return;
}
for (int i = index; i < nums.length; i++) {
// !res.contains(nums[i]
// 进行剪枝操作,添加新的元素要求不能在list中出现
if (!res.contains(nums[i])) {
res.add(nums[i]);
dfs(nums, index, res);
res.remove(res.size() - 1); // 因为要返回上一层,需要删除回溯时候遍历叶节点添加的值
}
}
}
}
class Solution {
List<List<Integer>> ans = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
List<Integer> res = new ArrayList<>();
dfs(nums, 0, res);
return ans;
}
public void dfs(int[] nums, int index, List<Integer> res) {
ans.add(new ArrayList<>(res));
for (int i = index; i < nums.length; i++) {
res.add(nums[i]);
dfs(nums, i + 1, res);
res.remove(res.size() - 1);
}
}
}