广告费内包括网站建设,网站设计要素 优帮云,广州市平安建设 网站,海外短视频服务器332.重新安排行程
本题是求解欧拉回路 / 欧拉通路的题目。
我们化简本题题意#xff1a;给定一个 n 个点 m 条边的图#xff0c;要求从指定的点出发#xff0c;经过所有的边恰好一次可以理解为给定起点的「一笔画」问题。本体的附加的要求是这个一笔画的路径需要是路径的字…332.重新安排行程
本题是求解欧拉回路 / 欧拉通路的题目。
我们化简本题题意给定一个 n 个点 m 条边的图要求从指定的点出发经过所有的边恰好一次可以理解为给定起点的「一笔画」问题。本体的附加的要求是这个一笔画的路径需要是路径的字典序最小。
一笔画问题与欧拉图或者半欧拉图有着紧密的联系下面给出定义
通过图中所有边恰好一次且行遍所有顶点的通路称为欧拉通路通过图中所有边恰好一次且行遍所有顶点的回路称为欧拉回路具有欧拉回路的无向图称为欧拉图具有欧拉通路但不具有欧拉回路的无向图称为半欧拉图。
因为本题保证至少存在一种合理的路径们只需要输出这条欧拉通路的路径即可。如果没有说明肯定存在答案那么这题又会变得更加复杂。
别看名字唬人但这题其实思路挺清晰的先用邻接表建图然后在图中深搜搜索过程中将走过的边邻接关系删除。
这个算法有个名字叫 hierholzer 算法。用于解决已知图中存在欧拉路径要找出一个欧拉路径的问题。过程如下
任选一个点为起点题目告诉你了遍历它所有邻接的边设置不同的分支。DFS 搜索访问邻接的点并且将走过的边邻接关系删除。如果走到的当前点已经没有相邻边了则将当前点推入 res。随着递归的出栈点不断推入 res 的开头最后就得到一个从起点出发的欧拉路径。
class Solution {
public:unordered_mapstring, vectorstring graph; // 存储机场与可飞往的目的地列表vectorstring result; // 存储最终的旅行路径void dfs(const string airport) {auto destinations graph[airport]; // 获取当前机场的目的地列表while (!destinations.empty()) { // 只要还有目的地就继续string next destinations.back(); // 获取字典序最小的目的地destinations.pop_back(); // 移除这个目的地dfs(next); // 递归访问下一个目的地}result.push_back(airport); // 在返回过程中构建路径}vectorstring findItinerary(vectorvectorstring tickets) {// 构建图for (auto ticket : tickets) {graph[ticket[0]].push_back(ticket[1]);}// 对每个机场的目的地列表按字典序降序排序以便在DFS中按升序处理for (auto pair : graph) {sort(pair.second.rbegin(), pair.second.rend());}// 开始深度优先搜索dfs(JFK);// 因为添加是在返回过程中完成的所以要反转结果列表reverse(result.begin(), result.end());return result;}
};
51. N皇后
这题大体思路和以前的是差不多的但实现细节出现了问题我最开始是采用的思路是用 used 数组从上往下标记不能放的位置for 循环内每放置一个皇后就将该行以下的不能放的位置标记然后递归到下一层遍历。
但实现这个思路的时候发现有问题我不好维护这个 used 数组因为涉及回溯这个数组很难回溯递归。
看了卡哥的题解发现卡哥的判断是否合法是从当前位置往上看的向上找两个斜角线上是否有皇后。
学习到了。
class Solution {
public:vectorvectorstring result;// n 为输入的棋盘大小// row 是当前递归到棋盘的第几行了void backtracking(int n, int row, vectorstring 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] .; // 回溯撤销皇后}}}bool isValid(int row, int col, vectorstring 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;}public:vectorvectorstring solveNQueens(int n) {result.clear();std::vectorstd::string chessboard(n, std::string(n, .));backtracking(n, 0, chessboard);return result;}
};
37. 解数独
这题递归思路有卡在判断是否合法了交给二刷的我去思考了。我就直接看题解了。
class Solution {
private:
bool backtracking(vectorvectorchar 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; // 放置kif (backtracking(board)) return true; // 如果找到合适一组立刻返回board[i][j] .; // 回溯撤销k}}return false; // 9个数都试完了都不行那么就返回false}}}return true; // 遍历完没有返回false说明找到了合适棋盘位置了
}
bool isValid(int row, int col, char val, vectorvectorchar 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;
}
public:void solveSudoku(vectorvectorchar board) {backtracking(board);}
};