332.重新安排行程
题目链接:332.重新安排行程
对于容器的选择,既然要将 tickets
转为其他容器,还不如一步到位。省的转为 vector
再排序什么的。
就像将之前的题目中 used
对应的值设置为 true
或 false
,而不用从数组中删除元素一样,同理可将容器也给出相应的信息用来标记。
因此容器选择 unordered_map<string, map<string, int>>
,其中 unordered_map
的选择是将航班的 起点 和 终点 构造映射关系。终点信息也包含航班次数,是和used
同样的原理:避免删除数组中元素。题目要求是字典序,所以选择终点结构为map<string, int>
。
整体容器表示为 <起点, <终点,起点到终点的次数>>
unordered_map<string, map<string, int>> targets;
for (auto& ticket : tickets) {
targets[ticket[0]][ticket[1]]++;
}
targets[ticket[0]][ticket[1]]++
:
targets[ticket[0]]
表示为 unordered_map
的 value
,即 map<string, int>
,
targets[ticket[0]][ticket[1]]
表示为 map<string, int>
的 value
class Solution {
unordered_map<string, map<string, int>> targets;//<起点, <终点,起点到终点的次数>>
bool backtracking(int ticketSum, vector<string>& res) {
if (res.size()/*通过res大小来确定飞了几次*/ == ticketSum + 1) {
return true;
}
for (auto& [k, v] : targets[res.back()]/*表示以res.back()为起点,对应的航班信息*/) {
if (v > 0/*票不为零,还有票*/) {
res.push_back(k);//起飞
--v;//少一张票
if (backtracking(ticketSum, res)) return true;
res.pop_back();
++v;
}
}
return false;
}
public:
vector<string> findItinerary(vector<vector<string>>& tickets) {
for (auto& ticket : tickets) {
targets[ticket[0]][ticket[1]]++;//将targets赋值
}
vector<string> res;
res.push_back("JFK");//起点
backtracking(tickets.size(), res);
return res;
}
};
for (auto& [k, v] : targets[res.back()]);
auto& [k, v] = targets[res.back()];
auto i = targets[res.back()];
i.begin()->first;
第一行和第二行代码的区别:
首先,第一行代码是在 targets
中搜索出 key
为 res.back()
的 value
,是有遍历的。
其次,第二行代码是错误的,map
不能使用结构化绑定来提取元素,结构化绑定是从数组或者 tuple
中提取元素,map
是关联容器,想要提取元素可以通过迭代器 begin()->first
等。
第四行表示 i
的类型为 targets
所对应的 value
的类型,而 i
的取值 和 res.back()
具体为多少无关。看看下面的例子
auto i1 = (int)3;
cout << is_same_v<decltype(i1), int>;//输出为1
51. N皇后
题目链接:51. N皇后
class Solution {
vector<vector<string>> res;
void backtracking(vector<string>& chessBoard, int n, int row) {
if (row == n) {
res.push_back(chessBoard);
return;
}
for (int i = 0; i < n; ++i) {
if (isValid(chessBoard, n, row, i)) {
chessBoard[row][i] = 'Q';
backtracking(chessBoard, n, row + 1);
chessBoard[row][i] = '.';
}
}
}
bool isValid(vector<string>& chessBoard, int n, int row, int col) {
//列
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:
vector<vector<string>> solveNQueens(int n) {
vector<string> chessBoard(n, string(n, '.'));
backtracking(chessBoard, n, 0);
return res;
}
};
37. 解数独
题目链接:37. 解数独
就是一个一个试出来,别想复杂了。计算机的优势就是算力强。
双层 for
循环定位坐标,递归寻找坐标所填的数字
class Solution {
bool backtracking(vector<vector<char>>& board) {
for (int i = 0; i < board.size(); ++i) {
for (int j = 0; j < board.size(); ++j) {
if (board[i][j] == '.') {
for (char ch = '1'; ch <= '9'; ++ch) {
if (isValid(board, i, j, ch)) {
board[i][j] = ch;
if (backtracking(board)) return true;
board[i][j] = '.';
}
}
return false;//1-9都试过了,还到了这一步,明显失败了
}
}
}
return true;//没有返回false,那就是对了,返回true
}
bool isValid(vector<vector<char>>& board, int row, int col, char ch) {
//行
for (int i = 0; i < 9; ++i) {
if (board[i][col] == ch)
return false;
}
//列
for (int j = 0; j < 9; ++j) {
if (board[row][j] == ch)
return false;
}
//3X3的格子
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] == ch)
return false;
}
}
return true;
}
public:
void solveSudoku(vector<vector<char>>& board) {
backtracking(board);
}
};
总结
留给第二次吧。画思维导图。