一、排列问题
排列是有序的,即{1,2}与{2,1}是两个排序。
1. 46【全排列】
- 题目: 给定一个不含重复数字的数组 nums ,返回其所有可能的全排列。你可以按任意顺序返回答案。
- 代码:
class Solution {List<List<Integer>> ansList = new ArrayList<>();List<Integer> path = new LinkedList<>();public List<List<Integer>> permute(int[] nums) {//排列是有序的,因此每一层用过的元素,在下一层还可以使用//但是需要记录在同一递归循环中是否使用过该元素//终止条件是path中的元素个数==nums.lengthboolean[] used = new boolean[nums.length];backtrack(nums,used);return ansList;}public void backtrack(int[] nums,boolean[] used){if(path.size() == nums.length) {ansList.add(new ArrayList<>(path));return;}for (int i = 0; i < nums.length; i++) {if(used[i]) continue;path.add(nums[i]);used[i] = true;backtrack(nums,used);path.removeLast();used[i] = false;}}
}
2. 47【全排列 II】
- 题目: 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
- 代码:
class Solution {public List<List<Integer>> ansList = new ArrayList<>();public List<Integer> path = new LinkedList<>();public List<List<Integer>> permuteUnique(int[] nums) {//本题与上一题的区别是本题含有重复数据//因此在每一递归层需要判断前面是否出现过相同元素//此外输入数组不一定是有序的,因此需要对数组进行排序Arrays.sort(nums);boolean[] used = new boolean[nums.length];backtrack(nums,used);return ansList;}public void backtrack(int[] nums,boolean[] used){if(path.size() == nums.length){ansList.add(new ArrayList<>(path));return;}for (int i = 0; i < nums.length; i++) {if(i>0 && nums[i]==nums[i-1]) {//如果上一个与当前元素相等的数被使用过,则代表两个数位于同一递归分支//我们需要对同一递归层中相同的元素进行剪枝,也就是说上一个元素不能被使用if(!used[i-1]) continue;}if(!used[i]){path.add(nums[i]);used[i] = true;backtrack(nums,used);path.removeLast();used[i] = false;}}}
}
二、棋盘问题
1. 51【N皇后】
- 题目: 按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
- 代码:
class Solution {List<List<String>> ansList = new ArrayList<>();public List<List<String>> solveNQueens(int n) {//N皇后问题:皇后的位置不能同行,同列,对角//棋盘是个n×n的数组,因此可以将第i行看成树的第i层//第j列看成树的第j个分支char[][] chessboard = new char[n][n];for(char[] cArr: chessboard){Arrays.fill(cArr,'.');}backtrack(n,chessboard,0);return ansList;}public void backtrack(int n,char[][] chessboard,int row){if(row == n){List<String> sList = new ArrayList<>();for (char[] cArr:chessboard) {sList.add(String.valueOf(cArr));}ansList.add(sList);}for (int col = 0; col <n ; col++) {if(isValid(n,chessboard,row,col)){chessboard[row][col] = 'Q';backtrack(n,chessboard,row+1);chessboard[row][col] ='.';}}}public boolean isValid(int n,char[][] chessboard,int row,int col){//因为一行只能有1个皇后,所以不需要检查第row行是否合法for (int i = 0; i < row; i++) {if(chessboard[i][col] == 'Q'){return false;}}//检查左上角for (int i=row-1,j=col-1; i>=0 && j>=0; i--,j--) {if(chessboard[i][j] == 'Q'){return false;}}//检查右上角for (int i=row-1,j=col+1; i>=0 && j<n; i--,j++) {if(chessboard[i][j] == 'Q'){return false;}}return true;}
}
2. 52【N皇后Ⅱ】
- 题目: n皇后问题 研究的是如何将 n 个皇后放置在 n × n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量。 - 代码:
class Solution {int num = 0;public int totalNQueens(int n) {char[][] board = new char[n][n];for(char[] c:board){Arrays.fill(c,'.');}backtrack(n,board,0);return num;}public void backtrack(int n,char[][] board,int row){if(row == n){num++;return;}for (int col = 0; col < n; col++) {if(isValid(row,col,board,n)){board[row][col] = 'Q';backtrack(n,board,row+1);board[row][col] = '.';}}}public boolean isValid(int row,int col,char[][] board,int n){for (int i = 0; i < row; i++) {if(board[i][col] == 'Q'){return false;}}for(int i=row-1,j=col-1;i>=0 && j>=0;i--,j--){if(board[i][j] == 'Q'){return false;}}for(int i=row-1,j=col+1;i>=0 && j<n;i--,j++){if(board[i][j] == 'Q'){return false;}}return true;}
}
3. 37【解数独】
- 题目: 编写一个程序,通过填充空格来解决数独问题。数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
数独的解法需 遵循如下规则:- 数字 1-9 在每一行只能出现一次。
- 数字 1-9 在每一列只能出现一次。
- 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
- 代码:
class Solution {public void solveSudoku(char[][] board) {//数独问题与N皇后问题不同,N皇后每次递归对行进行一次操作//而数独需要多次对同一行进行操作//所以使用两个for循环来进行递归//每次for循环找到符合条件的值就不在继续进行,因此回溯需要有boolean返回值backtrack(board);}public boolean backtrack(char[][] board){for (int i = 0; i < 9; i++) {for (int j = 0; j < 9; j++) {if(board[i][j] != '.') continue;for (char k = '1'; k <= '9' ; k++) {if(isValid(i,j,k,board)){board[i][j] = k;if(backtrack(board)) return true;board[i][j] = '.';}}return false;}}return true;}public boolean isValid(int row,int col,char k,char[][] board){//判断行for (int i = 0; i < 9; i++) {if(board[i][col] == k){return false;}}//判断列for (int i = 0; i < 9; i++) {if(board[row][i] == k){return false;}}for (int i = (row/3)*3; i < (row/3)*3+3; i++) {for (int j = (col/3)*3; j < (col/3)*3+3; j++) {if(board[i][j] == k){return false;}}}return true;}
}