第七章 回溯算法part06
大纲
● 332.重新安排行程
● 51. N皇后
● 37. 解数独
● 总结
leetcode 332
重新安排行程
思路
- 使用map记录同一出发地下的不同终点 终点用优先队列排序实现字典序
代码
class Solution {
List<String> res = new ArrayList<>();
Map<String, PriorityQueue<String>> map = new HashMap<>();
public List<String> findItinerary(List<List<String>> tickets) {
for (List<String> ticket : tickets) {
map.putIfAbsent(ticket.get(0), new PriorityQueue<>());
map.get(ticket.get(0)).offer(ticket.get(1));
}
dfs("JFK");
return res;
}
private void dfs(String s) {
PriorityQueue<String> p = map.get(s);
while (p != null && p.size() > 0) dfs(p.poll());
res.add(0, s);
}
}
leetcode 51
N皇后
class Solution {
List<List<String>> res = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
char[][] chessboard = new char[n][n];
for (char[] row : chessboard) Arrays.fill(row, '.');
backtrack(n, chessboard, 0);
return res;
}
private void backtrack(int n, char[][] chessboard, int row) {
if (row == n) {
res.add(arraysToList(chessboard));
return;
}
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] = '.';
}
}
}
private boolean isValid(int n, char[][] chessboard, int row, int col) {
// 检查行可攻击到的皇后
for (int i = 0; i < row; i++)
if (chessboard[i][col] == 'Q') return false;
// 列为循环体中控制 不会有同一行出现两个皇后
// 检查45°可攻击到的皇后
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--)
if (chessboard[i][j] == 'Q') return false;
// 检查135°可攻击到的皇后
for (int i = row - 1, j = col + 1; i >= 0 && j <= n - 1; i--, j++)
if (chessboard[i][j] == 'Q') return false;
return true;
}
private List<String> arraysToList(char[][] chessboard) {
List<String> item = new ArrayList<>();
for (char[] row : chessboard)
item.add(new String(row));
return item;
}
}
leetcode 37
解数独
class Solution {
public void solveSudoku(char[][] board) {
backtrack(board);
}
private 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;
}
private boolean isValid(int row, int col, int k, char[][] board) {
for (int i = 0; i < 9; i++) {
if (board[row][i] == k) return false;
if (board[i][col] == k) return false;
}
int startRow = (row / 3) * 3, startCol = (col / 3) * 3;
for (int i = startRow; i < startRow + 3; i++)
for (int j = startCol; j <startCol + 3; j++)
if (board[i][j] == k) return false;
return true;
}
}
总结
- 回溯章节总体来说比较简单 代码套路较多