332 重新安排行程
https://leetcode.cn/problems/reconstruct-itinerary/
graph 用 Map<from, group of to> 表示,其中 group of to需要既能排序,又能mark机票是不是还能用,于是用treemap<to, 几张>表示。如果不用Map表示顶点,也可以直接用tickets表示edges来表示图,要找衔接航班时每次扫描一遍。
class Solution { // 用 treemap<destination, usedOrNot> 不行,因为有重复机票
public List<String> findItinerary(List<List<String>> tickets) {
Map<String, TreeMap<String, Integer>> graph = new HashMap<>();
for (List<String> ticket : tickets) {
TreeMap<String, Integer> to = graph.getOrDefault(ticket.get(0), new TreeMap<>((a, b) -> a.compareTo(b)));
to.put(ticket.get(1), to.getOrDefault(ticket.get(1), 0) + 1);
graph.put(ticket.get(0), to);
}
List<String> result = new ArrayList<>();
result.add("JFK");
dfs(result, graph, tickets.size() + 1);
return result;
}
private boolean dfs(List<String> result, Map<String, TreeMap<String, Integer>> graph, int n) {
if (result.size() == n) {
return true;
}
TreeMap<String, Integer> to = graph.get(result.get(result.size() - 1));
if (to == null) return false;
for (Map.Entry<String, Integer> ticket : to.entrySet()){
if (ticket.getValue() == 0) continue;
String des = ticket.getKey();
to.put(des, ticket.getValue() - 1);
result.add(des);
if(dfs(result, graph, n)) return true; //从叶子提前返回
to.put(des, ticket.getValue() + 1);
result.remove(result.size() - 1);
}
return false;
}
}
/*class Solution {
private LinkedList<String> res;
private LinkedList<String> path = new LinkedList<>();
public List<String> findItinerary(List<List<String>> tickets) {
Collections.sort(tickets, (a, b) -> a.get(1).compareTo(b.get(1))); //destination按字母序
path.add("JFK");
boolean[] used = new boolean[tickets.size()];
backTracking((ArrayList) tickets, used);
return res;
}
public boolean backTracking(ArrayList<List<String>> tickets, boolean[] used) {
if (path.size() == tickets.size() + 1) {
res = new LinkedList(path);
return true;
}
for (int i = 0; i < tickets.size(); i++) {
if (!used[i] && tickets.get(i).get(0).equals(path.getLast())) {
path.add(tickets.get(i).get(1));
used[i] = true;
if (backTracking(tickets, used)) {
return true;
}
used[i] = false;
path.removeLast();
}
}
return false;
}
}*/
51 N皇后
https://leetcode.cn/problems/n-queens/description/
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> result = new ArrayList<>();
char[] oneRow = new char[n];
int[] positions = new int[n];
Arrays.fill(oneRow, '.');
dfs(result, oneRow, positions, 0); //如果第i行的选择不是显性写在参数里,那么它就藏在list of current selection里,如list的长度
return result;
}
private void dfs(List<List<String>> result, char[] oneRow, int[] positions, int i) {
if (i == positions.length) {
List<String> solution = new ArrayList<>();
for (int j = 0; j < i; j++) { //总共j行,每行上把positions[j]位置的char改为Q
oneRow[positions[j]] = 'Q';
solution.add(new String(oneRow));
oneRow[positions[j]] = '.'; //复原成一行....空置
}
result.add(solution);
return;
}
for (int j = 0; j < positions.length; j++) {
if (validate(positions, i, j)) {
positions[i] = j; //成功在 i 行上放一个列为 j的皇后
dfs(result, oneRow, positions, i + 1);
}
}
}
private boolean validate(int[] positions, int i, int j) {
for (int k = 0; k < i; k++) {
if (positions[k] == j || k + positions[k] == i + j || i - k == Math.abs(positions[k] - j)) return false;
}
return true;
}
}
37 解数独
https://leetcode.cn/problems/sudoku-solver/description/ 这题到了base case如何返回比较难懂。第一种解法每层决定一个格子一共81层结束。第二种解法最后一层扫完81格没有点剩下返回true,中间层找到点试着放数,一个可行会返回true, 放9个都不行返回false.
class Solution {
public void solveSudoku(char[][] board) {
boolean[][] col = new boolean[9][9], row = new boolean[9][9], cell = new boolean[9][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == '.') continue;
int num = board[i][j] - '1';
col[num][j] = true;
row[num][i] = true;
cell[num][(i / 3) * 3 + j / 3] = true;
}
}
dfs(0, 0, board, col, row, cell);
}
private boolean dfs(int i, int j, char[][] board, boolean[][] col, boolean[][] row, boolean[][] cell) {
if (j == 9) {
j = 0;
i++;
};
if (i == 9) return true;
if (board[i][j] != '.') return dfs(i, j + 1, board, col, row, cell);
for (int num = 0; num < 9; num++) {
if (col[num][j] || row[num][i] || cell[num][(i /3) * 3 + j / 3]) continue;
board[i][j] = (char)(num + '1'); //bug (char)
col[num][j] = row[num][i] = cell[num][(i /3) * 3 + j / 3] = true;
if (dfs(i, j + 1, board, col, row, cell)) return true;
board[i][j] = '.';
col[num][j] = row[num][i] = cell[num][(i /3) * 3 + j / 3] = false;
}
return false;
}
}
class Solution {
public void solveSudoku(char[][] board) {
boolean[][] rowUsed = new boolean[9][9];
boolean[][] colUsed = new boolean[9][9];
boolean[][] sqrUsed = new boolean[9][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] != '.') {
int num = board[i][j] - '1';
rowUsed[i][num] = true;
colUsed[j][num] = true;
sqrUsed[i / 3 * 3 + j / 3][num] = true;
}
}
}
dfs(board, rowUsed, colUsed, sqrUsed, count, 0);
}
private boolean dfs(char[][] board, boolean[][] rowUsed, boolean[][] colUsed, boolean[][] sqrUsed, int count, int start) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (i * 9 + j < start || board[i][j] != '.') continue;
for (int k = 0; k < 9; k++) {
if (rowUsed[i][k] || colUsed[j][k] || sqrUsed[i / 3 * 3 +j / 3][k]) continue;
rowUsed[i][k] = true;
colUsed[j][k] = true;
sqrUsed[i / 3 * 3 +j / 3][k] = true;
board[i][j] = (char)('1' + k);
if (dfs(board, rowUsed, colUsed, sqrUsed, i * 9 + j + 1)) return true;
rowUsed[i][k] = false;
colUsed[j][k] = false;
sqrUsed[i / 3 * 3 +j / 3][k] = false;
board[i][j] = '.';
}
return false; //如果9个数都试玩了还不行,那么返回false
}
}
return true; //如果棋盘全部遍历完没有返回false那么就排好了
}
}