36&&37 Valid Sudoku&&Sudoku Solver(Hard)
Valid Sudoku
Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules.
The Sudoku board could be partially filled, where empty cells are filled with the character '.'
.
A partially filled sudoku which is valid.
Note:
A valid Sudoku board (partially filled) is not necessarily solvable. Only the filled cells need to be validated.
暴力解法:
一行一行的看,一列一列的看,一个一个方格的看,
代码如下:
class Solution { public: bool isValidCell(vector<vector<char> > &board, int a, int b) { vector<bool> flag(9, false); int idx; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { idx = board[a + i][b + j] - '0'; if (idx > 0 && idx <= 9 && !flag[idx]) flag[idx] = true; else if (idx > 0 && idx <= 9 && flag[idx]) return false; } } return true; } bool isValidRow(vector<vector<char> > &board, int a) { vector<bool> flag(9, false); int idx; for (int j = 0; j < 9; ++j) { idx = board[a][j] - '0'; if (idx > 0 && idx <= 9 && !flag[idx]) flag[idx] = true; else if (idx > 0 && idx <= 9 && flag[idx]) return false; } return true; } bool isValidCol(vector<vector<char> > &board, int b) { vector<bool> flag(9, false); int idx; for (int i = 0; i < 9; ++i) { idx = board[i][b] - '0'; if (idx > 0 && idx <= 9 && !flag[idx]) flag[idx] = true; else if (idx > 0 && idx <= 9 && flag[idx]) return false; } return true; } bool isValidSudoku(vector<vector<char> > &board) { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (!isValidCell(board, 3 * i, 3 * j)) return false; } } for (int i = 0; i < 9; ++i) { if (!isValidRow(board, i)) return false; } for (int j = 0; j < 9; ++j) { if (!isValidCol(board, j)) return false; } return true; } };
使用Hash思想记录已经出现过的值,这样解法就变的特别容易了:
class Solution { public: bool isValidSudoku(vector<vector<char> > &board) { vector<vector<bool>> rows(9, vector<bool>(9,false)); vector<vector<bool>> cols(9, vector<bool>(9,false)); vector<vector<bool>> blocks(9, vector<bool>(9,false)); for(int i = 0; i < 9; i++) for(int j = 0; j < 9; j++) { if(board[i][j] == '.')continue; int num = board[i][j] - '1'; if(rows[i][num] || cols[j][num] || blocks[i - i%3 + j/3][num]) return false; rows[i][num] = cols[j][num] = blocks[i - i%3 + j/3][num] = true; } return true; } };
Sudoku Solver
Write a program to solve a Sudoku puzzle by filling the empty cells.
Empty cells are indicated by the character '.'
.
You may assume that there will be only one unique solution.
A sudoku puzzle...
...and its solution numbers marked in red.
很多题乍一看很难,是因为思路不清晰,只要思路清晰了,还是很简单的。
思路:
首先,每一行每一列的数字不能重合,其次把81个格子分成9个小格子,每一个格子里面的数字不能重合。
转:http://www.cnblogs.com/ganganloveu/p/3828401.html
这题跟N-Queens是一个套路,回溯法尝试所有解。
需要注意的区别是:
本题找到解的处理是return true,因此返回值为bool
N-Queen找到解的处理是保存解,因此返回值为void
对于每个空位'.',遍历1~9,check合理之后往下一个位置递归。
由于这里路径尝试本质上是有序的,即1~9逐个尝试,因此无需额外设置状态位记录已经尝试过的方向。
注意:只有正确达到最终81位置(即成功填充)的填充结果才可以返回,若不然,将会得到错误的填充。
因此辅助函数solve需要设为bool而不是void
class Solution { public: void solveSudoku(vector<vector<char> > &board) { solve(board, 0); } bool solve(vector<vector<char> > &board, int position) { if(position == 81) return true; int row = position / 9; int col = position % 9; if(board[row][col] == '.') { for(int i = 1; i <= 9; i ++) {//try each digit board[row][col] = i + '0'; if(check(board, position)) if(solve(board, position + 1)) //only return valid filling return true; board[row][col] = '.'; } } else { if(solve(board, position + 1)) //only return valid filling return true; } return false; } bool check(vector<vector<char> > &board, int position) { int row = position / 9; int col = position % 9; int gid; if(row >= 0 && row <= 2) { if(col >= 0 && col <= 2) gid = 0; else if(col >= 3 && col <= 5) gid = 1; else gid = 2; } else if(row >= 3 && row <= 5) { if(col >= 0 && col <= 2) gid = 3; else if(col >= 3 && col <= 5) gid = 4; else gid = 5; } else { if(col >= 0 && col <= 2) gid = 6; else if(col >= 3 && col <= 5) gid = 7; else gid = 8; } //check row, col, subgrid for(int i = 0; i < 9; i ++) { //check row if(i != col && board[row][i] == board[row][col]) return false; //check col if(i != row && board[i][col] == board[row][col]) return false; //check subgrid int r = gid/3*3+i/3; int c = gid%3*3+i%3; if((r != row || c != col) && board[r][c] == board[row][col]) return false; } return true; } };
回溯+hash的简介解法:
class Solution { private: bool line[9][9]; bool column[9][9]; bool block[3][3][9]; bool valid; vector<pair<int, int>> spaces; public: void dfs(vector<vector<char>>& board, int pos) { if (pos == spaces.size()) { valid = true; return; } auto [i, j] = spaces[pos]; for (int digit = 0; digit < 9 && !valid; ++digit) { if (!line[i][digit] && !column[j][digit] && !block[i / 3][j / 3][digit]) { line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true; board[i][j] = digit + '0' + 1; dfs(board, pos + 1); line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = false; } } } void solveSudoku(vector<vector<char>>& board) { memset(line, false, sizeof(line)); memset(column, false, sizeof(column)); memset(block, false, sizeof(block)); valid = false; for (int i = 0; i < 9; ++i) { for (int j = 0; j < 9; ++j) { if (board[i][j] == '.') { spaces.emplace_back(i, j); } else { int digit = board[i][j] - '0' - 1; line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true; } } } dfs(board, 0); } }; 作者:LeetCode-Solution 链接:https://leetcode-cn.com/problems/sudoku-solver/solution/jie-shu-du-by-leetcode-solution/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。