Day28_回溯算法
19. 重新安排行程
332. 重新安排行程
思路:
深搜 + 回溯
class Solution {
private:
// unordered_map<出发机场,map<出发机场,航班次数>> targets
unordered_map<string, map<string, int>> targets;
bool backtracking(int ticketNum, vector<string>& result) {
if (result.size() == ticketNum + 1) return true;
for (pair<const string, int>& target : targets[result[result.size() - 1]]) { // 每次从遍历到的最后一个地点开始搜
if (target.second > 0) {
result.push_back(target.first);
target.second--;
if (backtracking(ticketNum, result)) return true;
target.second++;
result.pop_back();
}
}
return false;
}
public:
vector<string> findItinerary(vector<vector<string>>& tickets) {
targets.clear();
vector<string> result;
for (const vector<string>& vec : tickets) {
targets[vec[0]][vec[1]]++; // 记录映射关系
}
result.push_back("JFK"); // 起始机场
backtracking(tickets.size(), result);
return result;
}
};
N 皇后
51. N 皇后
思路:
棋盘的高度是树的高度,棋盘的宽度是数的宽度
检查是否可以放皇后,前面的行已经放置好了,下面的行还是空的,只需检查是否和前面行的Q
冲突即可。
- 检查该列的前几行是否有
Q
- 检查左上斜行
- 检查右上斜行
class Solution {
private:
vector<vector<string>> result;
void backtracking(int n, int row, vector<string>& chessboard) {
if (n == row) {
result.push_back(chessboard);
return ;
}
for (int i = 0; i < n; i++) {
if (isVaild(n, row, i, chessboard)) {
chessboard[row][i] = 'Q';
backtracking(n, row + 1, chessboard);
chessboard[row][i] = '.';
}
}
}
bool isVaild(int n, int row, int col, vector<string>& chessboard) {
// 检查上面行的列
for (int i = 0; i < row; i++) {
if (chessboard[i][col] == 'Q')
return false; // 遇到不满足的情况直接返回(剪枝)
}
// 检查 45 度方向,只需要检查 row 之上的行是否正确,row 之下的行还没有填充
for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) { // 向右上检查
if (chessboard[i][j] == 'Q')
return false;
}
// 检查 135 度方向
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { // 向左上检查
if (chessboard[i][j] == 'Q')
return false;
}
return true;
}
public:
vector<vector<string>> solveNQueens(int n) {
result.clear();
vector<string> chessboard(n, string(n, '.'));
backtracking(n, 0, chessboard);
return result;
}
};
解数独
37. 解数独
思路:
在二维矩阵上的递归,由于要遍历每种情况,所以不需要特别写出口,遍历完所有情况后会跳出递归
class Solution {
private:
bool backtracking(vector<vector<char>>& board) {
for (int i = 0; i < board.size(); i++) {
for (int j = 0; j < board[i].size(); j++) {
if (board[i][j] != '.') continue;
for (char k = '1'; k <= '9'; k++) {
if (isVaild(i, j, k, board)) { // 判断(i, j) 这个位置放k是否合适
board[i][j] = k;
if (backtracking(board)) return true; // 找到满足的答案,直接返回
board[i][j] = '.';
}
}
return false; // 九个数都放不了,当前情况不满足,返回寻找下一个答案
}
}
return true;
}
bool isVaild(int row, int col, char val, vector<vector<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;
}
// 判断九宫格内是否重复
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;
}
public:
void solveSudoku(vector<vector<char>>& board) {
backtracking(board);
}
};