332. 重新安排行程 - 力扣(LeetCode)//困难。脑子不行。。跳过了。二刷再说。。。
51. N 皇后 - 力扣(LeetCode)//困难。理解思路就好写了。
class Solution {
private:
vector<vector<string>> result;
vector<string> path;
bool Isvaild(int n,int row,int col,const vector<string>& path){//核验某特定坐标是否满足要求。
for(int i=0;i<row;i++){//验证某列
if(path[i][col]=='Q')
return false;
}
for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){//验证对角线
if(path[i][j]=='Q')
return false;
}
for(int i=row-1,j=col+1;i>=0&&j<n;i--,j++){
if(path[i][j]=='Q')
return false;
}
return true;
}
void addpath(int n,int row){
if(row==n){
result.push_back(path);
return;
}
string s(n,'.');
path.push_back(s);
for(int i=0;i<n;i++){
if(Isvaild(n,row,i,path)){
path[row][i]='Q';
addpath(n,row+1);
path[row][i]='.';
}
}
path.pop_back();
}
public:
vector<vector<string>> solveNQueens(int n) {
result.clear();
path.clear();
if(n==1){
path.push_back("Q");
result.push_back(path);
}
else if(n>3){
addpath(n,0);
}
return result;
}
};
37. 解数独 - 力扣(LeetCode)//困难。看过思路也容易下手。
class Solution {
private:
int chartoint(const vector<vector<char>>& board,int row,int col){
int i=board[row][col]-'0';
return i;
}
void boardinsert(vector<vector<char>>& board,int row,int col,int nums){
char i=nums+'0';
board[row][col]=i;
}
bool Isvaild(const vector<vector<char>>& board,int row,int col,int temp){
char nums=temp+'0';
for(int i=0;i<9;i++){//检查同列
if(i!=row&&board[i][col]==nums) return false;
}
for(int i=0;i<9;i++){//检查同行
if(i!=col&&board[row][i]==nums) return false;
}
int temprow=3*(row/3);int tempcol=3*(col/3);
for(int i=temprow;i<temprow+3;i++){//检查3X3格
for(int j=tempcol;j<tempcol+3;j++){
if(i!=row&&j!=col&&board[i][j]==nums) return false;
}
}
return true;
}
bool findanswer(vector<vector<char>>& board){
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
if(board[i][j]!='.') continue;
for(int nums=1;nums<10;nums++){
if(Isvaild(board,i,j,nums)){
boardinsert(board,i,j,nums);
if(findanswer(board)) return true;
board[i][j]='.';
}
}
return false;//9个没找到即是无解。
}
}
return true;//递归的最深处,此时棋盘满了,因此需要返回true确认已经找到结果
}
public:
void solveSudoku(vector<vector<char>>& board) {
findanswer(board);
}
};
当结果唯一时最好使用带返回值的函数,方便找到一个解时立刻结束函数并返回
记录一个基于该算法下的优化方案(来自AI的讲解):
一、通过构建三个9位的bitset数组分别记录行列子格记录了当前行,当前列,当前子格已经占据的数字。使得判断速度提升。
二、先从两个for循环全图遍历,找到一个当前候选数最少的一个位置,从这个点开始递归回溯。因此树状图的第一层就比原先的算法少了。
这个算法比原来的快了2倍以上。。。
class Solution {
private:
vector<bitset<9>> row_flags; // 记录每行数字1-9的存在情况(位压缩)
vector<bitset<9>> col_flags; // 记录每列数字1-9的存在情况
vector<bitset<9>> block_flags; // 记录每个3x3子格数字1-9的存在情况
// 判断数字num是否可以填入(row, col)位置
bool isValid(int row, int col, int num) {
int d = num - 1; // 将数字1-9转换为bitset的索引0-8
int k = (row / 3) * 3 + (col / 3); // 计算子格索引(0-8)
// 检查行、列、子格中是否均未出现过该数字
return !row_flags[row][d] && !col_flags[col][d] && !block_flags[k][d];
}
// 回溯求解核心逻辑
bool backtrack(vector<vector<char>>& board) {
int min_count = 10; // 记录当前最小候选数数量
int best_row = -1, best_col = -1; // 候选数最少的位置坐标
vector<int> best_candidates; // 该位置的候选数字列表
// 遍历整个数独板,寻找候选数最少的空位(剪枝关键)
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) {
if (board[i][j] != '.') continue; // 跳过已填数字
vector<int> candidates;
// 收集当前空位的所有合法候选数字
for (int num = 1; num <= 9; ++num) {
if (isValid(i, j, num)) {
candidates.push_back(num);
}
}
if (candidates.empty()) return false; // 存在无解的空位,直接回溯
// 更新最优候选位置(优先处理可能性最少的位置)
if (candidates.size() < min_count) {
min_count = candidates.size();
best_row = i;
best_col = j;
best_candidates = candidates;
if (min_count == 1) break; // 已找到唯一候选,无需继续搜索
}
}
}
if (best_row == -1) return true; // 所有位置已填满,找到解
// 尝试所有候选数字
for (int num : best_candidates) {
int d = num - 1; // 转换为bitset索引
int k = (best_row / 3) * 3 + (best_col / 3); // 子格索引
// 更新状态标记
row_flags[best_row].set(d);
col_flags[best_col].set(d);
block_flags[k].set(d);
board[best_row][best_col] = num + '0'; // 填入数字
// 递归求解
if (backtrack(board)) return true;
// 回溯恢复状态
board[best_row][best_col] = '.';
row_flags[best_row].reset(d);
col_flags[best_col].reset(d);
block_flags[k].reset(d);
}
return false; // 当前路径无解
}
public:
void solveSudoku(vector<vector<char>>& board) {
// 初始化bitset数组
row_flags.resize(9);
col_flags.resize(9);
block_flags.resize(9);
// 预处理已有数字,填充标志位
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) {
if (board[i][j] != '.') {
int d = board[i][j] - '1'; // 字符转数字索引('1'->0 ... '9'->8)
int k = (i / 3) * 3 + (j / 3); // 计算子格索引
row_flags[i].set(d); // 标记行
col_flags[j].set(d); // 标记列
block_flags[k].set(d); // 标记子格
}
}
}
backtrack(board); // 启动回溯算法
}
};