2.0 dfs全排列問題
阿新 • • 發佈:2021-08-08
dfs+回溯寫題兩種思路
主要框架
public void dfs(選擇列表){
//1.找到結束條件
//2.遍歷所有可能性
//2.1做選擇
//2.2 遞迴呼叫自己進一步深度遍歷
//3.回撤選擇
}
- dfs函式的引數變數我覺得是越少越好,所以將一些不怎麼改變的變數設定為全域性變數更容易理清思路
1.遍歷的過程不停的往中間變數新增資料
static Set<String> res; static char[] ch; static boolean[] ch_helper; public static String[] permutation(String s) { res = new HashSet<>(); ch = s.toCharArray(); ch_helper = new boolean[ch.length]; dfs(""); return res.toArray(new String[res.size()]); } private static void dfs(String str) { //1.結束條件 if(str.length() == ch.length){ res.add(str); } //2.遍歷所有可能性 for(int i = 0; i < ch.length; i++){ if(ch_helper[i] != true){ ch_helper[i] = true; dfs(str + ch[i]); ch_helper[i] = false; } } }
static List<List<Integer>> res; static LinkedList<Integer> tmp; public static List<List<Integer>> permute(int[] nums) { res = new LinkedList<>(); tmp = new LinkedList<>(); dfs(nums); return res; } private static void dfs(int[] nums) { if(tmp.size() == nums.length){ res.add(new ArrayList<>(tmp)); return; } for(int num : nums){ if(tmp.contains(num)){ continue; } tmp.add(num); dfs(nums); tmp.removeLast(); }
2. 遍歷的過程改變原列表,這種一般會從下標0開始
static List<String> res; static char[] ch; public static String[] permutation(String s) { res = new LinkedList<>(); ch = s.toCharArray(); dfs(0); return res.toArray(new String[res.size()]); } private static void dfs(int i) { //1.結束條件 if (i == ch.length - 1){ res.add(String.valueOf(ch)); return; } //2.選擇列表 Set<Character> set = new HashSet<>(); for(int idx = i; idx < ch.length; idx++){ if(set.contains(ch[idx])) continue; set.add(ch[idx]); //2.1選擇 swap(ch, idx, i); //2.2 進一步 dfs(i + 1); //3.回溯 swap(ch, idx, i); } } private static void swap(char[] ch, int idx, int i) { char tmp = ch[idx]; ch[idx] = ch[i]; ch[i] = tmp; }
- 麼有剪枝
static List<String> res;
static char[] ch;
public static String[] permutation(String s) {
res = new LinkedList<>();
ch = s.toCharArray();
dfs(0);
return res.toArray(new String[res.size()]);
}
private static void dfs(int i) {
//1.結束條件
if (i == ch.length - 1){
res.add(String.valueOf(ch));
return;
}
//2.選擇列表
for(int idx = i; idx < ch.length; idx++){
set.add(ch[idx]);
//2.1選擇
swap(ch, idx, i);
//2.2 進一步
dfs(i + 1);
//3.回溯
swap(ch, idx, i);
}
}
private static void swap(char[] ch, int idx, int i) {
char tmp = ch[idx];
ch[idx] = ch[i];
ch[i] = tmp;
}
- 帶剪枝
static List<String> res;
static char[] ch;
public static String[] permutation(String s) {
res = new LinkedList<>();
ch = s.toCharArray();
dfs(0);
return res.toArray(new String[res.size()]);
}
private static void dfs(int i) {
//1.結束條件
if (i == ch.length - 1){
res.add(String.valueOf(ch));
return;
}
//2.選擇列表
Set<Character> set = new HashSet<>();
for(int idx = i; idx < ch.length; idx++){
if(set.contains(ch[idx]))
continue;
set.add(ch[idx]);
//2.1選擇
swap(ch, idx, i);
//2.2 進一步
dfs(i + 1);
//3.回溯
swap(ch, idx, i);
}
}
private static void swap(char[] ch, int idx, int i) {
char tmp = ch[idx];
ch[idx] = ch[i];
ch[i] = tmp;
}
public class solveNQueens {
public static List<List<String>> solveNQueens(int n) {
char[][] queens = new char[n][n]; List<List<String>> res = new LinkedList<>(); backtrack(queens, res,0, n); return res; }
private static void backtrack(char[][] queens, List<List<String>> res, int i, int n) {
//結束,生成結果 if (i == n){
res.add(generateBoard(queens)); return; }
//如果放得下 for(int j = 0; j < n; j++){
if (valid(queens, i, j)){
queens[i][j] = 'Q'; backtrack(queens, res,i + 1, n); //撤銷 queens[i][j] = '.'; }
}
}
private static List<String> generateBoard(char[][] queens) {
List<String> path = new ArrayList<>(); for (int i = 0; i < queens.length; i++) {
for(int j = 0; j < queens[0].length; j++)
if (queens[i][j] != 'Q')
queens[i][j] = '.'; path.add(new String(queens[i])); }
return path; }
//row表示第幾行,col表示第幾列 private static boolean valid(char[][] chess, int row, int col) {
//判斷當前列有沒有皇后,因為他是一行一行往下走的, //我們只需要檢查走過的行數即可,通俗一點就是判斷當前 //座標位置的上面有沒有皇后 for (int i = 0; i < row; i++) {
if (chess[i][col] == 'Q') {
return false; }
}
//判斷當前座標的右上角有沒有皇后 for (int i = row - 1, j = col + 1; i >= 0 && j < chess.length; i--, j++) {
if (chess[i][j] == 'Q') {
return false; }
}
//判斷當前座標的左上角有沒有皇后 for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (chess[i][j] == 'Q') {
return false; }
}
return true; }
}
package leetcode.dfs.hot301_removeInvalidParentheses;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 301. 刪除無效的括號
* 給你一個由若干括號和字母組成的字串 s ,刪除最小數量的無效括號,使得輸入的字串有效。
*
* 返回所有可能的結果。答案可以按 任意順序 返回。
*
* 示例 1:
*
* 輸入:s = "()())()"
* 輸出:["(())()","()()()"]
* 示例 2:
*
* 輸入:s = "(a)())()"
* 輸出:["(a())()","(a)()()"]
* 示例 3:
*
* 輸入:s = ")("
* 輸出:[""]
*/
public class removeInvalidParentheses_2 {
static int len;
static String str;
public static List<String> removeInvalidParentheses(String s) {
len = s.length();
str = s;
Set<String> res = new HashSet<>();
int leftRemove = 0, rightRemove = 0;
for(int i = 0; i < len; i++){
if(s.charAt(i) == '(') leftRemove ++;
else if(s.charAt(i) == ')'){
if(leftRemove == 0){
rightRemove ++;
}else{
leftRemove--;
}
}
}
dfs(0, 0, 0, leftRemove, rightRemove, "", res);
return new ArrayList<>(res);
}
public static void dfs(int idx, int leftCount, int rightCount, int leftRemove, int rightRemove, String tmp, Set<String> res){
// 0. 結束條件
if(idx == len){
if(leftRemove == 0 && rightRemove == 0) {
res.add(tmp);
}
return;
}
// 1. 刪除當前字元
if(str.charAt(idx) == '(' && leftRemove > 0){
dfs(idx + 1, leftCount, rightCount, leftRemove - 1, rightRemove,tmp, res);
}
if(str.charAt(idx) == ')' && rightRemove > 0){
dfs(idx + 1, leftCount, rightCount, leftRemove, rightRemove - 1,tmp, res);
}
// 2. 保留當前字元,分三種情況
tmp = tmp+str.charAt(idx);
// 2.1 保留(
if(str.charAt(idx) == '('){
dfs(idx + 1, leftCount+1, rightCount, leftRemove, rightRemove,tmp, res);
}else if(str.charAt(idx) == ')') {
// 保留 )
if (leftCount > rightCount)
dfs(idx + 1, leftCount, rightCount + 1, leftRemove, rightRemove, tmp, res);
// else{
// 剪枝啦,當rightCount >= leftCount時已經無解決
// }
}else{
// 2.3 保留其他字元
dfs(idx + 1, leftCount, rightCount, leftRemove, rightRemove, tmp, res);
}
}
public static void main(String[] args) {
String str = "()())()";
System.out.println(str);
List<String> res = removeInvalidParentheses(str);
System.out.println(res);
}
}
class Solution {
Set<String> res;
boolean[] visited;
char[] chars;
public String[] permutation(String s) {
visited = new boolean[s.length()];
chars = s.toCharArray();
res = new HashSet<>();
dfs("");
return res.toArray(new String[res.size()]);
}
public void dfs(String tmp){
if(tmp.length() == visited.length){
res.add(tmp);
return;
}
for(int i = 0; i < chars.length; i++){
if(visited[i] == false){
visited[i] = true;
dfs(tmp + chars[i]);
visited[i] = false;
}
}
}
}