1.重新安排行程
class Solution {
private:
// <出发机场,<到达机场,航班次数>>
unordered_map<string,map<string,int>> targets;
bool bracktracking(int ticketNum,vector<string>& result){
// 遇到的机场个数,如果达到了(航班数量+1),那么我们就找到了一个行程,把所有航班串在一起了。
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(bracktracking(ticketNum,result)) return true;
result.pop_back();
target.second++;
}
}
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");
bracktracking(tickets.size(),result);
return result;
}
};
思路:hard题,我看看就行了
可以将这个过程类比为在一个迷宫中寻找通往终点的路径。targets 可以看作是迷宫地图,记录了每个位置可以通往的下一个位置以及通往该位置的航班次数。backtracking 函数就像是一个人在迷宫中尝试不同的路径,每次都选择一个可行的航班前往下一个目的地,直到找到通往终点的路径或者走入死胡同。最终,findItinerary 函数就像是一个人在迷宫入口处开始寻找通往出口的路径。
在进行targets“地图绘制”时:
“
首先,代码中定义了一个私有变量 targets,它是一个 unordered_map,其中的值是一个 map。这个数据结构用来记录每个出发机场与到达机场以及航班次数的映射关系。
然后,代码中定义了一个私有函数 backtracking,它用来进行回溯搜索。在每一步搜索中,它会检查当前到达的机场是否有可用的航班,如果有的话就选择一个航班前往该目的地,并标记这个航班已经被使用过。然后递归调用 backtracking 函数,继续搜索下一个机场。如果找到了一个符合条件的完整路径(即 result 中包含了所有的机票),则返回 true;否则,回溯到上一步,并尝试其他可能的航班。
接着是公共函数 findItinerary,它接受一个二维 vector tickets 作为输入。在这个函数中,首先对 targets 进行清空,然后遍历 tickets,更新 targets 中的映射关系。接着将起始机场 "JFK" 加入结果列表 result 中,并调用 backtracking 函数进行回溯搜索,最后返回找到的结果路径。
”
2.N皇后
代码:
class Solution {
private:
vector<vector<string>> result;
bool Isvalid(int row,int col,vector<string>& chessboard,int n){
// 检查列
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;
}
void backtracking(int n,int row,vector<string>& chessboard){
if(row == n){
result.push_back(chessboard);
return;
}
for(int col = 0;col < n;col++){
if(Isvalid(row,col,chessboard,n)){
chessboard[row][col] = 'Q';
backtracking(n,row + 1,chessboard);
chessboard[row][col] = '.';
}
}
}
public:
vector<vector<string>> solveNQueens(int n) {
vector<string> chessboard (n,string(n,'.'));
backtracking(n,0,chessboard);
return result;
}
};
思路:其实步骤和之前学的没什么区别。就是i这里用col表示,path这里用chessboard表示。
我这次的错误是在判断对角线上是否有其他皇后时,循环的判断条件写错了,没有加等号。边界也是需要我们去处理判断的,所以要有等号。(我在这上面到底栽了多少跟头啊啊啊)
3.解数独
代码:
class Solution {
private:
bool Isvaild(int row,int col,char val,vector<vector<char>>& board){
for(int i = 0;i < 9;i++){
if(board[i][col] == val){
return false;
}
}
for(int j = 0;j < 9;j++){
if(board[row][j] == 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;
}
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++){
if(Isvaild(i,j,k,board)){
board[i][j] = k;
if(backtracking(board)) return true;
board[i][j] = '.';
}
}
return false;
}
}
}
return true;
}
public:
void solveSudoku(vector<vector<char>>& board) {
backtracking(board);
}
};
思路:这道题其实和n皇后很像,只不过,我们这次要在每一个空格处填写数字,所以这里用到的for循环应该是两层,行和列对应一个空。
难点在于返回放在程序中的位置。在使用过一次递归函数时,应该及时检查它的返回值,如果为true,及时向上次返回,一路绿灯。
如果每一个都没有及时返回,那就会走完整个两层的for循环,因此在这里返回false。
如果都做到了及时的返回,那就不会走到return false那里,直接返回给了上一层递归,因此我们在整个递归函数的末尾放return true。
这道题,我又出错了,我在检查所处的9个单元方格时,忘记把它们对应除以的商*3了。以及不知道为什么一直超时,把那个检查行列是否重复的那里,把循环条件改成i<9 j <9 就过了。也不知道为什么()