1.重新安排行程
使用 unordered_map 存储出发机场, map作为底层为红黑树,因此存入的数据是有序的,来按序存储到达的机场以及可以到达的次数
在遍历的时候由于到达机场的存储使用的是map有序的,因此第一个符合条件的行程就是最优的行程
class Solution {
public:
// targets统计的是出发机场tarets.first 和多个对应的到达机场 map<string, int>
unordered_map<string, map<string, int>> targets;
bool backtrcking(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(backtrcking(ticketNum, result)) return true;
result.pop_back();
target.second++;
}
}
return false;
}
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"); // 起始机场
backtrcking(tickets.size(), result);
return result;
}
};
- 自己理解写出来的方法,但是会超时
class Solution {
public:
// 1. 每个tickets中的票都只能用一次, 使用used数组进行判断
// 2. 递归终止条件,startIndex = tickets.size()
// 3. 单层逻辑: 将当前遍历的票添加到结果,再将以ticket[1]为首的 ticket数组进行遍历
vector<vector<string>> result; // 记录所有的路径
vector<string> path; // 记录最短的路程
int used[301] = { 0 };
void backtracking(vector<vector<string>>& tickets, string nextStart) {
// 注意这里的终止条件, 需要==tickets.size()
if (path.size() == tickets.size()) {
path.push_back(nextStart);
result.push_back(path);
path.pop_back();
return;
}
for (int i = 0; i < tickets.size(); i++) {
if (used[i] != 1 && tickets[i][0] == nextStart) {
path.push_back(nextStart);
used[i] = 1;
backtracking(tickets, tickets[i][1]);
used[i] = 0;
path.pop_back();
}
}
}
vector<string> findItinerary(vector<vector<string>>& tickets) {
backtracking(tickets, "JFK");
sort(result.begin(), result.end());
// for (auto tickt : result) {
// for (auto name : tickt) {
// cout << name << " ";
// }
// cout << endl;
// }
return result[0];
}
};
2. N皇后问题
- 分析步骤
- 判断皇后位置是否合法的函数 (判断当前位置所在列是否有其他棋子; 判断当前位置左上角45度是否有其他棋子;判断当前位置右上角135度是否有其他棋子)
- 递归的返回值和参数 返回值为void即可, 参数 需要棋盘的大小n,当前递归的行数row,棋盘现在放置的皇后chessboard
- 递归终止条件:当遍历可以达到最后一层并且成功遍历完 即 row==n的时候 代表当前chessboard放置是正确的
- 单层递归逻辑:每一行(row) 都从前向后遍历col(0-n),判断该位置放置皇后是否合法 chessVaild
class Solution {
public:
vector<vector<string>> result;
// 1. 判断棋子位置合法的函数
bool chessVaild(int row, int col, vector<string>& chessboard, int n){
// 不合法的位置存在于 同一列与 45° 和 135° 角的两个斜线上
// 判断是否在同一列上
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; i--, j++){
if(chessboard[i][j] == 'Q'){
return false;
}
}
return true;
}
// 2. 确定参数和返回值: 参数为当前的棋子数row(也就是当前的行数), 棋盘的大小n, 和当前行存放的棋子 chessborad
void backtracking(int n, int row, vector<string>& chessboard){ // n表示当前行数和列数
// 3.终止条件,当row==n的时候,也就是到了最后一行了,则将当前结果存入到result
if(n == row){
result.push_back(chessboard);
return ;
}
// 4. 确定单层递归逻辑
for(int col=0; col<n; col++){
if(chessVaild(row, col, chessboard, n)){
chessboard[row][col] = 'Q';
backtracking(n, row+1, chessboard);
chessboard[row][col] = '.';
}
}
}
vector<vector<string>> solveNQueens(int n) {
result.clear();
vector<string> chessboard(n, string(n, '.'));
backtracking(n, 0, chessboard);
return result;
}
};
3. 解数独
class Solution {
public:
// 判断数字放置这里是否合法
// 1.这一行是否合法
// 2.这一列是否合法
// 3.在3x3的宫内是否合法
bool isValid(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++) { // 判断9方格里是否重复
for (int j = startCol; j < startCol + 3; j++) {
if (board[i][j] == val ) {
return false;
}
}
}
return true;
}
bool backtracking(vector<vector<char>>& board) {
for (int i = 0; i < board.size(); i++) { // 遍历行
for (int j = 0; j < board[0].size(); j++) { // 遍历列
if (board[i][j] == '.') {
for (char k = '1'; k <= '9'; k++) { // (i, j) 这个位置放k是否合适
if (isValid(i, j, k, board)) {
board[i][j] = k; // 放置k
if (backtracking(board)) return true; // 如果找到合适一组立刻返回
board[i][j] = '.'; // 回溯,撤销k
}
}
return false; // 9个数都试完了,都不行,那么就返回false
}
}
}
return true; // 遍历完没有返回false,说明找到了合适棋盘位置了
}
void solveSudoku(vector<vector<char>>& board) {
backtracking(board);
}
};