重新安排行程
力扣连接:332. 重新安排行程(困难)
1.回溯方法
图解步骤
关键点:
- Collections.sort(tickets,(a,b)->a.get(1).compareTo(b.get(1)));
- 返回值为 boolean
递归代码
class Solution {
List<String> result = new ArrayList<>();
LinkedList<String> tmp = new LinkedList<>();
public List<String> findItinerary(List<List<String>> tickets) {
//字典序排序
Collections.sort(tickets,(a,b)->a.get(1).compareTo(b.get(1)));
tmp.add("JFK");
backtracking(tickets, new int[tickets.size()]);
return result;
}
//用boolean控制 只能有一种情况
public boolean backtracking(List<List<String>> tickets, int[] used){
if(tmp.size()==tickets.size()+1){
result = new ArrayList<>(tmp);
return true;
}
for(int i=0;i<tickets.size();i++){
//used[i]==0表示没用过
if(used[i]==0 && tickets.get(i).get(0).equals(tmp.getLast())){
tmp.add(tickets.get(i).get(1));
used[i] = 1;
if(backtracking(tickets, used)){
return true;
}
used[i] = 0;
tmp.removeLast();
}
}
return false;
}
}
N 皇后
力扣连接:51. N 皇后(困难)
1.回溯的方法
图解步骤
关键点:
- 只要搜索到了树的叶子节点,说明就找到了皇后们的合理位置了。
递归代码
class Solution {
List<List<String>> result = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
char[][] plate = new char[n][n];
for (char[] c : plate) {
Arrays.fill(c, '.');
}
backtracking(plate, 0);
return result;
}
public void backtracking(char[][] plate, int rowIndex){
if(rowIndex==plate[0].length){
result.add(Array2List(plate));
return;
}
for(int i=0; i<plate[0].length; i++){
if(isValid(rowIndex, i, plate)){
plate[rowIndex][i] = 'Q';
backtracking(plate, rowIndex+1);
plate[rowIndex][i] = '.';
}
}
}
public List<String> Array2List(char[][] chessboard) {
List<String> list = new ArrayList<>();
for (char[] c : chessboard) {
list.add(String.copyValueOf(c)); //整行copy
}
return list;
}
public boolean isValid(int row, int col, char[][] plate){
int n = plate[0].length;
// 检查列
for (int i=0; i<row; i++) { // 忽略了行,且i<row 相当于剪枝
if (plate[i][col] == 'Q') {
return false;
}
}
//检查45°
for(int i=row-1,j=col-1; i>=0&&j>=0; i--,j--){
if(plate[i][j]=='Q'){
return false;
}
}
//和135°
for(int i=row-1,j=col+1; i>=0&&j<n; i--,j++){
if(plate[i][j]=='Q'){
return false;
}
}
return true;
}
}
解数独
力扣连接:37. 解数独(困难)
棋盘搜索问题可以使用回溯法暴力搜索,只不过这次我们要做的是二维递归
图解步骤
关键点:
-
注意这里return false的地方,这里放return false 是有讲究的。
因为如果一行一列确定下来了,这里尝试了9个数都不行,说明这个棋盘找不到解决数独问题的解!
那么会直接返回, 这也就是为什么没有终止条件也不会永远填不满棋盘而无限递归下去!
-
判断棋盘是否合法有如下三个维度:
同行是否重复
同列是否重复
9宫格里是否重复
代码
class Solution {
public void solveSudoku(char[][] board) {
backtracking(board);
}
public boolean backtracking(char[][] board){
//遍历行
for(int i=0;i<board.length;i++){
//遍历列
for(int j=0;j<board[0].length;j++){
//找到空格
if(board[i][j]=='.'){
//分别填入1-9
for(char k='1';k<='9';k++){
//校验可行性
if(isValid(i, j, k, board)){
board[i][j]=k;
if(backtracking(board)) return true;
board[i][j]='.';
}
}
//9个数都不满足
return false;
}
}
}
return true;
}
/**
* 判断棋盘是否合法有如下三个维度:
* 同行是否重复
* 同列是否重复
* 9宫格里是否重复
*/
private boolean isValid(int row, int col, char val, char[][] board){
// 同行是否重复
for (int i = 0; i < 9; i++){
if (board[row][i] == val){
return false;
}
}
// 同列是否重复
for (int j = 0; j < 9; j++){
if (board[j][col] == val){
return false;
}
}
// 9宫格里是否重复
int startRow = (row / 3) * 3;
int startCol = (col / 3) * 3;
for (int i = startRow; i < startRow + 3; i++){
for (int j = startCol; j < startCol + 3; j++){
if (board[i][j] == val){
return false;
}
}
}
return true;
}
}