代码如下:
class Solution {
public List<List<Integer>> permute(int[] nums) {
int len = nums.length;
List<List<Integer>> res = new ArrayList<>();
if (null == nums || 0 == len) {
return res;
}
// 栈的实现,java语言要求
Deque<Integer> path = new ArrayDeque<>();
// 标记数字是否有使用过,默认为false没有使用过
boolean[] used = new boolean[len];
dfs(nums, len, 0, path, used, res);
return res;
}
// 题目要求所有的搜索结果,所有找到一个结果返回上一层后还可以继续找下一个结果。如果题目要求只要一个结果,dfs可以返回boolean
// 在一些地方可以及时退出
private void dfs(int[] nums, int len, int depth, Deque<Integer> path, boolean[] used, List<List<Integer>> res) {
// 递归结束的条件,depth从0开始,只要等于nums长度即可结束递归
if (depth == len) {
// path保存的是一个引用,dfs结束后,path内没有任何元素,所以每次用res保存结果时必须新建一个path的副本(即new // ArrayList(path))
res.add(new ArrayList(path));
return;
}
for (int i = 0; i < len; i ++) {
if (used[i] == false) {
used[i] = true;
// 往栈中添加一个元素
path.addLast(nums[i]);
dfs(nums, len, depth + 1, path, used, res);
// 删除栈中一个元素
path.removeLast();
used[i] = false;
}
}
}
}
题解:给出的序列中数字有重复的,所以要考虑剪枝。
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
int len = nums.length;
List<List<Integer>> res = new ArrayList<>();
if (null == nums || 0 == len) {
return res;
}
// 剪枝的前提,排序后可以剪枝
Arrays.sort(nums);
Deque<Integer> path = new ArrayDeque<>();
boolean[] used = new boolean[len];
dfs(nums, len, 0, path, used, res);
return res;
}
private void dfs(int[] nums, int len, int depth, Deque<Integer> path, boolean[] used, List<List<Integer>> res) {
if (depth == len) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < len; i ++) {
if (used[i]) {
continue;
}
// 剪枝
if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
continue;
}
used[i] = true;
path.addLast(nums[i]);
dfs(nums, len, depth + 1, path, used, res);
used[i] = false;
path.removeLast();
}
}
}
题解:1.由于给出的序列,可以无限制重复被选取。所以不能使用boolean used[]数组来标记给出的序列是否使用过。2.题目要求解集不能包含重复的组合。所以用begin指针标记使用的数字从哪里开始。即不能使用当前序列数字之前的数字。
代码如下:
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
int len = candidates.length;
List<List<Integer>> res = new ArrayList<>();
if (0 == len) {
return res;
}
// 为了剪枝让给定的序列排序
Arrays.sort(candidates);
Deque<Integer> path = new ArrayDeque<>();
dfs(candidates, 0, target, path, res);
return res;
}
// 由于给定的序列数字可以无限制重复被选取,所以不用boolean used[]数组。
private void dfs(int[] candidates, int begin, int target, Deque<Integer> path, List<List<Integer>> res) {
if (0 == target) {
res.add(new ArrayList<>(path));
return;
}
// 解集不能包含重复的组合,所以选取下一个数字是必须从当前数字往后尝试
for (int i = begin; i < candidates.length; i ++) {
// 剪枝,由于已经排好序(从小到大),所以只要target < candidates[i]即可跳出循环
if (target - candidates[i] < 0) {
break;
}
path.addLast(candidates[i]);
// 由于给定的序列数字可以无限制重复被选取,所以下一个数字还可以选取当前这个数字
dfs(candidates, i, target - candidates[i], path, res);
path.removeLast();
}
}
}
代码如下:
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
int len = candidates.length;
List<List<Integer>> res = new ArrayList<>();
if (null == candidates || 0 == len || target < 0) {
return res;
}
Arrays.sort(candidates);
Deque<Integer> path = new ArrayDeque<>();
dfs(candidates, 0, target, path, res);
return res;
}
private void dfs(int[] candidates, int begin, int target, Deque<Integer> path, List<List<Integer>> res) {
if (0 == target) {
res.add(new ArrayList<>(path));
return;
}
for (int i = begin; i < candidates.length; i ++) {
// 大剪枝
if (target - candidates[i] < 0) {
break;
}
// 小剪枝
if (i > begin && candidates[i] == candidates[i - 1]) {
continue;
}
path.addLast(candidates[i]);
dfs(candidates, i + 1, target - candidates[i], path, res);
path.removeLast();
}
}
}
代码如下:
class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<>();
Deque<Integer> path = new ArrayDeque<>();
dfs(n, 0, k, 1, path, res);
return res;
}
private void dfs(int n, int depth, int k, int begin, Deque<Integer> path, List<List<Integer>> res) {
if (depth == k) {
res.add(new ArrayList<>(path));
return;
}
for (int i = begin; i <= n; i ++) {
path.addLast(i);
dfs(n, depth + 1, k, i + 1, path, res);
path.removeLast();
}
}
}
代码如下:
class Solution {
public List<List<Integer>> subsets(int[] nums) {
int len = nums.length;
List<List<Integer>> res = new ArrayList<>();
res.add(new ArrayList<>());
if (null == nums || 0 == len) {
return res;
}
Deque<Integer> path = new ArrayDeque<>();
for (int i = 1; i <= len; i ++) {
dfs(nums, 0, i, 0, path, res);
}
return res;
}
private void dfs(int[] nums, int depth, int k, int begin, Deque<Integer> path, List<List<Integer>> res) {
if (depth == k) {
res.add(new ArrayList<>(path));
return;
}
for (int i = begin; i < nums.length; i ++) {
path.addLast(nums[i]);
dfs(nums, depth + 1, k, i + 1, path, res);
path.removeLast();
}
}
}
代码如下:
public List<List<Integer>> subsetsWithDup(int[] nums) {
int len = nums.length;
List<List<Integer>> res = new ArrayList<>();
if (null == nums || 0 == len) {
return res;
}
// 剪枝的前提:排序
Arrays.sort(nums);
Deque<Integer> path = new ArrayDeque<>();
for (int i = 0; i <= nums.length; i ++) {
dfs(nums, 0, 0, i, path, res);
}
return res;
}
private void dfs(int[] nums, int depth, int begin, int k, Deque<Integer> path, List<List<Integer>> res) {
if (depth == k) {
res.add(new ArrayList<>(path));
return;
}
for (int i = begin; i < nums.length; i ++) {
if (i > begin && nums[i] == nums[i - 1]) {
continue;
}
path.addLast(nums[i]);
dfs(nums, depth + 1, i + 1, k, path, res);
path.removeLast();
}
}
题解:1.题目没有要求题目要求解集可以重复,每一层遍历序列可以全部遍历。
代码如下:
class Solution {
private int sum = 0;
public String getPermutation(int n, int k) {
int[] nums = new int[n];
boolean[] used = new boolean[n];
Deque<Integer> path = new ArrayDeque<>();
for (int i = 0; i < n; i ++) {
nums[i] = i + 1;
}
dfs(nums, 0, used, path, k);
List<Integer> list = new ArrayList<>(path);
StringBuilder sb = new StringBuilder();
for (int i : list) {
sb.append(i + "");
}
return sb.toString();
}
// 解法一:
// private void dfs(int[] nums, int depth, boolean[] used, Deque path, int k) {
// if (depth == nums.length) {
// sum ++;
// return;
// }
// for (int i = 0; i < nums.length; i ++) {
// if (used[i]) {
// continue;
// }
// used[i] = true;
// path.addLast(nums[i]);
// dfs(nums, depth + 1, used, path, k);
// if (sum == k) {
// return;
// }
// used[i] = false;
// path.removeLast();
// }
// }
// 解法二:
private boolean dfs(int[] nums, int depth, boolean[] used, Deque<Integer> path, int k) {
if (depth == nums.length) {
sum ++;
return sum == k;
}
for (int i = 0; i < nums.length; i ++) {
if (used[i]) {
continue;
}
used[i] = true;
path.addLast(nums[i]);
if (dfs(nums, depth + 1, used, path, k)) {
return true;
}
used[i] = false;
path.removeLast();
}
return false;
}
}
代码如下:
class Solution {
public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
// 注意:假如一开始的值和newColor一样,直接返回结果,不然会出现死循环
if (image[sr][sc] == newColor) {
return image;
}
int value = image[sr][sc];
boolean[][] used = new boolean[image.length][image[0].length];
dfs(image, sr, sc, newColor, value, used);
return image;
}
private void dfs(int[][] image, int i, int j, int newColor, int value, boolean[][] used) {
// 递归出口条件判断
if (i < 0 || i >= image.length || j < 0 || j >= image[0].length || image[i][j] != value || used[i][j]) {
return;
}
// 标记
used[i][j] = true;
image[i][j] = newColor;
// 走不通的方向路径
dfs(image, i - 1, j, newColor, value, used);
dfs(image, i, j + 1, newColor, value, used);
dfs(image, i + 1, j, newColor, value, used);
dfs(image, i, j - 1,newColor, value, used);
}
}
代码如下:
class Solution {
public int numIslands(char[][] grid) {
if (null == grid || 0 == grid.length) {
return 0;
}
int sum = 0;
for (int i = 0; i < grid.length; i ++) {
for (int j = 0; j < grid[0].length; j ++) {
if (grid[i][j] == '1') {
sum ++;
dfs(grid, i, j);
}
}
}
return sum;
}
private void dfs(char[][] grid, int i, int j) {
if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == '0') {
return;
}
grid[i][j] = '0';
dfs(grid, i - 1, j);
dfs(grid, i, j + 1);
dfs(grid, i + 1, j);
dfs(grid, i, j - 1);
}
}
题解:首先先从边界上开始查找是否有0的位置,将边界上0位置上所关联到的0都设置为Y,其次遍历这个区域,全部将0设置为x,最后将Y设置为0.
代码如下:
class Solution {
public void solve(char[][] board) {
if (null == board || 0 == board.length) {
return;
}
for (int j = 0; j < board[0].length; j ++) {
dfs(board, 0, j);
dfs(board, board.length - 1, j);
}
for (int i = 1; i < board.length - 1; i ++) {
dfs(board, i, 0);
dfs(board, i, board[0].length - 1);
}
for (int i = 0; i < board.length; i ++) {
for (int j = 0; j < board[0].length; j ++) {
if (board[i][j] == 'O') {
board[i][j] = 'X';
}
}
}
for (int i = 0; i < board.length; i ++) {
for (int j = 0; j < board[0].length; j ++) {
if (board[i][j] == 'Y') {
board[i][j] = 'O';
}
}
}
}
private void dfs(char[][] board, int i, int j) {
if (i < 0 || i >= board.length || j < 0 || j >= board[0].length || board[i][j] == 'X' || board[i][j] == 'Y') {
return;
}
board[i][j] = 'Y';
dfs(board, i - 1, j);
dfs(board, i, j + 1);
dfs(board, i + 1, j);
dfs(board, i, j - 1);
}
}
代码如下:
class Solution {
public boolean exist(char[][] board, String word) {
if (null == board) {
return false;
}
if (null == word || 0 == word.length()) {
return true;
}
int[][] state = new int[board.length][board[0].length];
for (int i = 0; i < board.length; i ++) {
for (int j = 0; j < board[0].length; j ++) {
if (dfs(i, j, 0, board, word, state)) {
return true;
}
}
}
return false;
}
private boolean dfs(int i, int j, int index, char[][] board, String word, int[][] state) {
if (index == word.length()) {
return true;
}
if (i < 0 || i >= board.length || j < 0 || j >= board[0].length || state[i][j] == 1) {
return false;
}
state[i][j] = 1;
if (board[i][j] == word.charAt(index)) {
boolean res = dfs(i - 1, j, index + 1, board, word, state) ||
dfs(i + 1, j, index + 1, board, word, state) ||
dfs(i, j - 1, index + 1, board, word, state) ||
dfs(i, j + 1, index + 1, board, word, state);
state[i][j] = 0;
return res;
}
state[i][j] = 0;
return false;
}
}
代码如下:
class Solution {
public List<String> letterCombinations(String digits) {
if (null == digits || 0 == digits.length()) {
return new ArrayList<>();
}
String[][] cs = {
{
}, {
}, {
"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"}};
List<String> res = new ArrayList<>();
String str = new String();
dfs(0,cs, digits,str,res);
return res;
}
private void dfs(int step, String[][] cs, String digits, String str, List<String> res) {
// step = 0
if (step == digits.length() - 1) {
if (digits.charAt(step) == '7' || digits.charAt(step) == '9') {
for (int i = 0; i < 4; i ++) {
String s1 = str + cs[digits.charAt(step) - '0'][i];
res.add(s1);
}
} else {
for (int i = 0; i < 3; i ++) {
String s1 = str + cs[digits.charAt(step) - '0'][i];
res.add(s1);
}
}
return;
}
if (digits.charAt(step) == '7' || digits.charAt(step) == '9') {
for (int i = 0; i < 4; i ++) {
str += cs[digits.charAt(step) - '0'][i];
dfs(step + 1, cs,digits, str,res);
str = str.substring(0,str.length() - 1);
}
} else {
for (int i = 0; i < 3; i ++) {
str += cs[digits.charAt(step) - '0'][i];
dfs(step + 1, cs,digits, str,res);
str = str.substring(0,str.length() - 1);
}
}
return;
}
}
代码如下:
class Solution {
public List<String> letterCasePermutation(String S) {
int len = S.length();
List<String> res = new ArrayList<>();
if (0 == len) {
return res;
}
char[] charArray = new char[len];
dfs(S, len, 0, charArray, res);
return res;
}
// start 从0开始
private void dfs(String S, int len, int start, char[] charArray, List<String> res) {
if (start == len) {
res.add(new String(charArray));
return;
}
charArray[start] = S.charAt(start);
dfs(S, len, start + 1, charArray, res);
if (Character.isLetter(S.charAt(start))) {
// 大小写转化
charArray[start] = (char)(S.charAt(start) ^ (1 << 5));
dfs(S, len, start + 1, charArray, res);
}
}
}
代码如下:
class Solution {
public List<String> generateParenthesis(int n) {
List<String> res = new ArrayList<>();
dfs("", n, n, res);
return res;
}
private void dfs(String curStr, int left, int right, List<String> res) {
if (0 == left && 0 == right) {
res.add(curStr);
return;
}
if (left > right) {
return;
}
if (right > 0) {
dfs(curStr + ")", left, right - 1, res);
}
if (left > 0) {
dfs(curStr + "(", left - 1, right, res);
}
}
}
题解:参考资料
代码如下:
class Solution {
private int n;
private boolean[] col;
private boolean[] master;
private boolean[] slave;
private List<List<String>> res;
public List<List<String>> solveNQueens(int n) {
this.n = n;
col = new boolean[n];
master = new boolean[2 * n - 1];
slave = new boolean[2 * n - 1];
res = new ArrayList<>();
Deque<Integer> stack = new ArrayDeque<>();
dfs(0, stack);
return res;
}
private void dfs(int row, Deque<Integer> stack) {
if (row == n) {
List<String> board = covert2Board(stack, n);
res.add(board);
return;
}
for (int i = 0; i < n; i ++) {
if (!col[i] && !master[row + i] && !slave[row - i + n - 1]) {
stack.addLast(i);
col[i] = true;
master[row + i] = true;
slave[row - i + n - 1] = true;
dfs(row + 1, stack);
col[i] = false;
master[row + i] = false;
slave[row - i + n - 1] = false;
stack.removeLast();
}
}
}
// 保存一个结果的stack,皇后数量:n
private List<String> covert2Board(Deque<Integer> stack, int n) {
List<String> board = new ArrayList<>();
for (Integer num : stack) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i ++) {
sb.append(".");
}
sb.replace(num, num + 1, "Q");
board.add(sb.toString());
}
return board;
}
}
题解:参考资料
代码如下:
// 方块,行,列都是从0开始
class Solution {
private boolean[][] rows;
private boolean[][] cols;
private boolean[][] blocks;
public void solveSudoku(char[][] board) {
rows = new boolean[9][10];
cols = new boolean[9][10];
blocks = new boolean[9][10];
for (int i = 0; i < board.length; i ++) {
for (int j = 0; j < board[0].length; j ++) {
if (board[i][j] != '.') {
rows[i][board[i][j] - '0'] = true;
cols[j][board[i][j] - '0'] = true;
blocks[blockIndex(i, j)][board[i][j] - '0'] = true;
}
}
}
dfs(0, board);
}
// 题目要求只要找到一种解法即可,找到后就返回,而且还要保留这一种结果。
// 找到后通过返回true即可向上退出。如果题目要求返回所有的结果即dfs方法返回void
private boolean dfs(int depth, char[][] board) {
if (depth == 81) {
return true;
}
int row = rowIndex(depth);
int col = colIndex(depth);
if (board[row][col] != '.') {
return dfs(depth + 1, board);
} else {
for (int i = 1; i < 10; i ++) {
if (rows[row][i] || cols[col][i] || blocks[blockIndex(row, col)][i]) {
continue;
}
board[row][col] = (char)('0' + i);
rows[row][i] = true;
cols[col][i] = true;
blocks[blockIndex(row, col)][i] = true;
if (dfs(depth + 1, board)) {
return true;
}
board[row][col] = '.';
rows[row][i] = false;
cols[col][i] = false;
blocks[blockIndex(row, col)][i] = false;
}
}
return false;
}
private int blockIndex(int i, int j) {
return i / 3 * 3 + j / 3;
}
private int rowIndex(int depth) {
return depth / 9;
}
private int colIndex(int depth) {
return depth % 9;
}
}