leetcode 37. Sudoku Solver 36. Valid Sudoku 数独问题
三星机试也考了类似的题目,只不过是要针对给出的数独修改其中三个错误数字,总过10个测试用例只过了3个与世界500强无缘了
36. 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.
Subscribe to see which companies asked this question
Idea
Just go through all you see (like "7 in row 3") and check for duplicates.
Solution 1
Using Counter. One logical line, seven physical lines.
def isValidSudoku(self, board):
return 1 == max(collections.Counter(
x
for i, row in enumerate(board)
for j, c in enumerate(row)
if c != '.'
for x in ((c, i), (j, c), (i/3, j/3, c))
).values() + [1])
The + [1] is only for the empty board, where max would
get an empty list and complain. It's not necessary to get it accepted here, as the empty board isn't among the test cases, but it's good to have.
Solution 2
Using len(set).
def isValidSudoku(self, board):
seen = sum(([(c, i), (j, c), (i/3, j/3, c)]
for i, row in enumerate(board)
for j, c in enumerate(row)
if c != '.'), [])
return len(seen) == len(set(seen))
Solution 3
Using any.
def isValidSudoku(self, board):
seen = set()
return not any(x in seen or seen.add(x)
for i, row in enumerate(board)
for j, c in enumerate(row)
if c != '.'
for x in ((c, i), (j, c), (i/3, j/3, c)))
Solution 4
Iterating a different way.
def isValidSudoku(self, board):
seen = sum(([(c, i), (j, c), (i/3, j/3, c)]
for i in range(9) for j in range(9)
for c in [board[i][j]] if c != '.'), [])
return len(seen) == len(set(seen))
Clean and Easy82ms Python
class Solution(object):
def isValidSudoku(self, board):
"""
:type board: List[List[str]]
:rtype: bool
"""
big = set()
for i in xrange(0,9):
for j in xrange(0,9):
if board[i][j]!='.':
cur = board[i][j]
if (i,cur) in big or (cur,j) in big or (i/3,j/3,cur) in big:
return False
big.add((i,cur))
big.add((cur,j))
big.add((i/3,j/3,cur))
37. 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.
Subscribe to see which companies asked this question
最快的解决方案:
Sharing my 2ms C++ solution with comments and explanations.
3,937 views
Update: there's a follow-up
0ms solution which is even more optimized
This is one of the fastest Sudoku solvers I've ever written. It is compact enough - just 150 lines of C++ code with comments. I thought it'd be interesting to share it, since it combines several techniques like
reactive network update propagation and backtracking with very aggressive pruning.
The algorithm is online - it starts with an empty board and as you add numbers to it, it starts solving the Sudoku.
Unlike in other solutions where you have bitmasks of allowed/disallowed values per row/column/square, this solution track bitmask for every(!) cell, forming a set of constraints for the allowed values for each particular
cell. Once a value is written into a cell, new constraints are immediately propagated to row, column and 3x3 square of the cell. If during this process a value of other cell can be unambiguously deduced - then the value is set, new constraints are propagated,
so on.... You can think about this as an implicit reactive network of cells.
If we're lucky (and we'll be lucky for 19 of 20 of Sudokus published in magazines) then Sudoku is solved at the end (or even before!) processing of the input.
Otherwise, there will be empty cells which have to be resolved. Algorithm uses backtracking for this purpose. To optimize it, algorithm starts with the cell with the smallest ambiguity. This could be improved even
further by using priority queue (but it's not implemented here). Backtracking is more or less standard, however, at each step we guess the number, the reactive update propagation comes back into play and it either quickly proves that the guess is unfeasible
or significantly prunes the remaining search space.
It's interesting to note, that in this case taking and restoring snapshots of the compact representation of the state is faster than doing backtracking rollback by "undoing the moves".
class Solution {
struct cell // encapsulates a single cell on a Sudoku board
{
uint8_t value; // cell value 1..9 or 0 if unset
// number of possible (unconstrained) values for the cell
uint8_t numPossibilities;
// if bitset[v] is 1 then value can't be v
bitset<10> constraints;
cell() : value(0), numPossibilities(9),constraints() {};
};
array<array<cell,9>,9> cells;
// sets the value of the cell to [v]
// the function also propagates constraints to other cells and deduce new values where possible
bool set(int i, int j, int v)
{
// updating state of the cell
cell& c = cells[i][j];
if (c.value == v)
return true;
if (c.constraints[v])
return false;
c.constraints = bitset<10>(0x3FE); // all 1s
c.constraints.reset(v);
c.numPossibilities = 1;
c.value = v;
// propagating constraints
for (int k = 0; k<9; k++) {
// to the row:
if (i != k && !updateConstraints(k, j, v))
return false;
// to the column:
if (j != k && !updateConstraints(i, k, v))
return false;
// to the 3x3 square:
int ix = (i / 3) * 3 + k / 3;
int jx = (j / 3) * 3 + k % 3;
if (ix != i && jx != j && !updateConstraints(ix, jx, v))
return false;
}
return true;
}
// update constraints of the cell i,j by excluding possibility of 'excludedValue'
// once there's one possibility left the function recurses back into set()
bool updateConstraints(int i, int j, int excludedValue)
{
cell& c = cells[i][j];
if (c.constraints[excludedValue]) {
return true;
}
if (c.value == excludedValue) {
return false;
}
c.constraints.set(excludedValue);
if (--c.numPossibilities > 1)
return true;
for (int v = 1; v <= 9; v++) {
if (!c.constraints[v]) {
return set(i, j, v);
}
}
assert(false);
}
// backtracking state - list of empty cells
vector<pair<int, int>> bt;
// find values for empty cells
bool findValuesForEmptyCells()
{
// collecting all empty cells
bt.clear();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (!cells[i][j].value)
bt.push_back(make_pair(i, j));
}
}
// making backtracking efficient by pre-sorting empty cells by numPossibilities
sort(bt.begin(), bt.end(), [this](const pair<int, int>&a, const pair<int, int>&b) {
return cells[a.first][a.second].numPossibilities < cells[b.first][b.second].numPossibilities; });
return backtrack(0);
}
// Finds value for all empty cells with index >=k
bool backtrack(int k)
{
if (k >= bt.size())
return true;
int i = bt[k].first;
int j = bt[k].second;
// fast path - only 1 possibility
if (cells[i][j].value)
return backtrack(k + 1);
auto constraints = cells[i][j].constraints;
// slow path >1 possibility.
// making snapshot of the state
array<array<cell,9>,9> snapshot(cells);
for (int v = 1; v <= 9; v++) {
if (!constraints[v]) {
if (set(i, j, v)) {
if (backtrack(k + 1))
return true;
}
// restoring from snapshot,
// note: computationally this is cheaper
// than alternative implementation with undoing the changes
cells = snapshot;
}
}
return false;
}
public:
void solveSudoku(vector<vector<char>> &board) {
cells = array<array<cell,9>,9>(); // clear array
// Decoding input board into the internal cell matrix.
// As we do it - constraints are propagated and even additional values are set as we go
// (in the case if it is possible to unambiguously deduce them).
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++) {
if (board[i][j] != '.' && !set(i, j, board[i][j] - '0'))
return; // sudoku is either incorrect or unsolvable
}
}
// if we're lucky we've already got a solution,
// however, if we have empty cells we need to use backtracking to fill them
if (!findValuesForEmptyCells())
return; // sudoku is unsolvable
// copying the solution back to the board
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++) {
if (cells[i][j].value)
board[i][j] = cells[i][j].value + '0';
}
}
}
};
Simple and Clean Solution / C++
871 views
bool check(vector<vector<char>> &board, int i, int j, char val)
{
int row = i - i%3, column = j - j%3;
for(int x=0; x<9; x++) if(board[x][j] == val) return false;
for(int y=0; y<9; y++) if(board[i][y] == val) return false;
for(int x=0; x<3; x++)
for(int y=0; y<3; y++)
if(board[row+x][column+y] == val) return false;
return true;
}
bool solveSudoku(vector<vector<char>> &board, int i, int j)
{
if(i==9) return true;
if(j==9) return solveSudoku(board, i+1, 0);
if(board[i][j] != '.') return solveSudoku(board, i, j+1);
for(char c='1'; c<='9'; c++)
{
if(check(board, i, j, c))
{
board[i][j] = c;
if(solveSudoku(board, i, j+1)) return true;
board[i][j] = '.';
}
}
return false;
}
public: void solveSudoku(vector<vector>& board) { solveSudoku(board, 0, 0); }
c++ clear solution using dfs, beating 90% c++ coder.
690 views
class Solution {
public:
bool col[10][10],row[10][10],f[10][10];
bool flag = false;
void solveSudoku(vector<vector<char>>& board) {
memset(col,false,sizeof(col));
memset(row,false,sizeof(row));
memset(f,false,sizeof(f));
for(int i = 0; i < 9;i++){
for(int j = 0; j < 9;j++){
if(board[i][j] == '.') continue;
int temp = 3*(i/3)+j/3;
int num = board[i][j]-'0';
col[j][num] = row[i][num] = f[temp][num] = true;
}
}
dfs(board,0,0);
}
void dfs(vector<vector<char>>& board,int i,int j){
if(flag == true) return ;
if(i >= 9){
flag = true;
return ;
}
if(board[i][j] != '.'){
if(j < 8) dfs(board,i,j+1);
else dfs(board,i+1,0);
if(flag) return;
}
else{
int temp = 3*(i/3)+j/3;
for(int n = 1; n <= 9; n++){
if(!col[j][n] && !row[i][n] && !f[temp][n]){
board[i][j] = n + '0';
col[j][n] = row[i][n] = f[temp][n] = true;
if(j < 8) dfs(board,i,j+1);
else dfs(board,i+1,0);
col[j][n] = row[i][n] = f[temp][n] = false;
if(flag) return;
}
}
board[i][j] = '.';
}
}
};
13-line Python solution, dfs, beats 47.79%
77 views
def solveSudoku(self, board):
def dfs():
for i, row in enumerate(board):
for j, char in enumerate(row):
if char == '.':
for x in s9 - {row[k] for k in r9} - {board[k][j] for k in r9} - \
{board[i / 3 * 3 + m][j / 3 * 3 + n] for m in r3 for n in r3}:
board[i][j] = x
if dfs(): return True
board[i][j] = '.'
return False
return True
r3, r9, s9 = range(3), range(9), {'1', '2', '3', '4', '5', '6', '7', '8', '9'}
dfs()
参考文献:
http://www.cnblogs.com/felixfang/p/3705754.html
leetcode 37. Sudoku Solver 36. Valid Sudoku 数独问题的更多相关文章
- LeetCode:36. Valid Sudoku,数独是否有效
LeetCode:36. Valid Sudoku,数独是否有效 : 题目: LeetCode:36. Valid Sudoku 描述: Determine if a Sudoku is valid, ...
- 【LeetCode】36. Valid Sudoku 解题报告(Python)
[LeetCode]36. Valid Sudoku 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址 ...
- [Leetcode][Python]36: Valid Sudoku
# -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 36: Valid Sudokuhttps://oj.leetcode.com ...
- [LeetCode] 36. Valid Sudoku 验证数独
Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to th ...
- [leetcode]36. Valid Sudoku验证数独
Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to th ...
- leetCode 36.Valid Sudoku(有效的数独) 解题思路和方法
Valid Sudoku Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku bo ...
- 【leetcode】36. Valid Sudoku(判断能否是合法的数独puzzle)
Share Determine if a 9 x 9 Sudoku board is valid. Only the filled cells need to be validated accordi ...
- 【一天一道LeetCode】#36. Valid Sudoku
一天一道LeetCode 本系列文章已全部上传至我的github,地址:https://github.com/Zeecoders/LeetCode 欢迎转载,转载请注明出处 (一)题目 Determi ...
- LeetCode 36 Valid Sudoku
Problem: Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku board ...
随机推荐
- 【SPOJ839】Optimal Marks 网络流
You are given an undirected graph G(V, E). Each vertex has a mark which is an integer from the range ...
- Linux下安装3.0以上的python
Linux下自带的python2.7是不建议删除的,很多系统软件依赖python2.7,但是现在我们学习python一般需要python3.0,下面介绍安装python3.0. 1.进入python官 ...
- async/await,了解一下?
上一篇博客我们在现实使用和面试角度讲解了Promise(原文可参考<面向面试题和实际使用谈promise>),但是Promise 的方式虽然解决了 callback hell,但是这种方式 ...
- RHEL 7修改ssh默认端口号
RHEL7修改默认端口号(默认port22)初次安装系统完毕后默认情况下系统已经启动了sshd服务当然我们也可以先进行检查: 步骤1,检查是否已安装ssh服务 步骤2,检查服务是否已开启 如上图所示显 ...
- 美链BEC合约漏洞技术分析
这两天币圈链圈被美链BEC智能合约的漏洞导致代币价值几乎归零的事件刷遍朋友圈.这篇文章就来分析下BEC智能合约的漏洞 漏洞攻击交易 我们先来还原下攻击交易,这个交易可以在这个链接查询到. 我截图给大家 ...
- CAP原理和BASE思想和ACID模型
问题的解读 对于上面三个例子,相信大家一定看出来了,我们的终端用户在使用不同的计算机产品时对于数据一致性的需求是不一样的: 1.有些系统,既要快速地响应用户,同时还要保证系统的数据对于任意客户端都是真 ...
- 从 python 中 axis 参数直觉解释 到 CNN 中 BatchNorm 的工作方式(Keras代码示意)
1. python 中 axis 参数直觉解释 网络上的解释很多,有的还带图带箭头.但在高维下是画不出什么箭头的.这里阐述了 axis 参数最简洁的解释. 假设我们有矩阵a, 它的shape是(4, ...
- public、protected、default、private区别
public.protected.default.private: 修饰符 本类 同包 子类 其他 public √ √ √ √ protected √ √ √ × default √ √ × × p ...
- 转:rabbitmq——用户管理
原文:http://my.oschina.net/hncscwc/blog/262246?p={{currentPage-1}} 安装最新版本的rabbitmq(3.3.1),并启用managemen ...
- delphi 线程教学第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行
第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行 以 Ado 为例,常见的方法是拖一个 AdoConnection 在窗口上(或 DataModule 中), 再配合 AdoQ ...