LeetCode 37 - Sudoku Solver


https://leetcode.com/problems/sudoku-solver/
Write a program to solve a Sudoku puzzle by filling the empty cells.
A sudoku solution must satisfy all of the following rules:
  1. Each of the digits 1-9 must occur exactly once in each row.
  2. Each of the digits 1-9 must occur exactly once in each column.
  3. Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.
Empty cells are indicated by the character '.'.

A sudoku puzzle...

...and its solution numbers marked in red.
Note:
  • The given board contain only digits 1-9 and the character '.'.
  • You may assume that the given Sudoku puzzle will have a single unique solution.
  • The given board size is always 9x9
https://leetcode.com/problems/sudoku-solver/discuss/15752/Straight-Forward-Java-Solution-Using-Backtracking
    public void solveSudoku(char[][] board) {
        if(board == null || board.length == 0)
            return;
        solve(board);
    }
    
    public boolean solve(char[][] board){
        for(int i = 0; i < board.length; i++){
            for(int j = 0; j < board[0].length; j++){
                if(board[i][j] == '.'){
                    for(char c = '1'; c <= '9'; c++){//trial. Try 1 through 9
                        if(isValid(board, i, j, c)){
                            board[i][j] = c; //Put c for this cell
                            
                            if(solve(board))
                                return true; //If it's the solution return true
                            else
                                board[i][j] = '.'; //Otherwise go back
                        }
                    }
                    
                    return false;
                }
            }
        }
        return true;
    }
    
    private boolean isValid(char[][] board, int row, int col, char c){
        for(int i = 0; i < 9; i++) {
            if(board[i][col] != '.' && board[i][col] == c) return false; //check row
            if(board[row][i] != '.' && board[row][i] == c) return false; //check column
            if(board[3 * (row / 3) + i / 3][ 3 * (col / 3) + i % 3] != '.' && 
board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == c) return false; //check 3*3 block
        }
        return true;
    }
http://www.cnblogs.com/grandyang/p/4421852.html
https://www.programcreek.com/2014/05/leetcode-sudoku-solver-java/
    bool isValid(vector<vector<char> > &board, int i, int j) {
        for (int col = 0; col < 9; ++col) {
            if (col != j && board[i][j] == board[i][col]) return false;
        }
        for (int row = 0; row < 9; ++row) {
            if (row != i && board[i][j] == board[row][j]) return false;
        }
        for (int row = i / 3 * 3; row < i / 3 * 3 + 3; ++row) {
            for (int col = j / 3 * 3; col < j / 3 * 3 + 3; ++col) {
                if ((row != i || col != j) && board[i][j] == board[row][col]) return false;
            }
        }
        return true;
    }

http://blog.csdn.net/linhuanmars/article/details/20748761
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.
这道题的方法就是用在N-Queens中介绍的常见套路。简单地说思路就是循环处理子问题,对于每个格子,带入不同的9个数,然后判合法,如果成立就递归继续,结束后把数字设回空。大家可以看出代码结构和N-Queens是完全一样的。判合法可以用Valid Sudoku做为subroutine,但是其实在这里因为每次进入时已经保证之前的board不会冲突,所以不需要判断整个盘,只需要看当前加入的数字和之前是否冲突就可以,这样可以大大提高运行效率,毕竟判合法在程序中被多次调用。
这个方法是一个非常典型的套路,大部分NP问题的都是可以这个方法,比如N-QueensCombination SumCombinationsPermutations等。
public void solveSudoku(char[][] board) {
    if(board == null || board.length != 9 || board[0].length !=9)
        return;
    helper(board,0,0);
}
private boolean helper(char[][] board, int i, int j)
{
    if(j>=9)
        return helper(board,i+1,0);
    if(i==9)
    {
        return true;
    }
    if(board[i][j]=='.')
    {
        for(int k=1;k<=9;k++)
        {
            board[i][j] = (char)(k+'0');
            if(isValid(board,i,j))
            {
                if(helper(board,i,j+1))
                    return true;
            }
            board[i][j] = '.';
        }
    }
    else
    {
        return helper(board,i,j+1);
    }
    return false;
}
private boolean isValid(char[][] board, int i, int j)
{
    for(int k=0;k<9;k++)
    {
        if(k!=j && board[i][k]==board[i][j])
            return false;
    }
    for(int k=0;k<9;k++)
    {
        if(k!=i && board[k][j]==board[i][j])
            return false;
    }        
    for(int row = i/3*3; row<i/3*3+3; row++)
    {
        for(int col=j/3*3; col<j/3*3+3; col++)
        {
            if((row!=i || col!=j) && board[row][col]==board[i][j])
                return false;
        }
    }
    return true;
}
X. http://codesniper.blogspot.com/2015/03/37-sudoku-solver-leetcode.html
Recursively fill the empty cell with available number that make the sudouku board valid, if all numbers were not valid in this cell, backtrack to last cell and iteratively try next number until all cells are filled with number.
This is a kind of standard solution for all recursion problem. 1.Find the base case or terminating case.Usually was written in the fist line of the recursion function(if(...) ...return) 2. Iteratively try valid one and go to next cell, if the current trial doesn't work, reset the current trial to original value and try next possibility.  So the code always looks like :
setValue(i) / addItem(i);
helper(...,i+1);
setValue(original)/removeItem(i);
 public void solveSudoku(char[][] board) {  
    if(board==null || board.length==0 || board[0].length==0) return;  
    boolean[][] row= new boolean[9][9];  
    boolean[][] col= new boolean[9][9];  
    boolean[][] block=new boolean[9][9];  
    for(int i=0;i<board.length;i++){  
      for(int j=0;j<board[0].length;j++){  
        if(board[i][j]<='9' && board[i][j]>='1'){  
          int num=board[i][j]-'1';  
          int bnum=(i/3)*3+j/3;  
          if(row[i][num] || col[j][num] || block[bnum][num]) return;  
          row[i][num] = col[j][num] = block[bnum][num] =true;  
        }  
      }  
    }  
    helper(board,0,row,col,block);  
   }  
    public boolean helper(char[][] board, int ind, boolean[][] row, boolean[][] col, boolean[][] block){  
      if(ind==81) return true;  
      int i=ind/9;  
      int j=ind%9;  
      int b=(i/3)*3+j/3;  
      if(board[i][j]=='.'){  
        for(int k=1;k<=9;k++){  
          if((!row[i][k-1]) && (!col[j][k-1]) && (!block[b][k-1])){  
            board[i][j]=(char)('0'+k);  
            row[i][k-1] =col[j][k-1] =block[b][k-1]=true;  
            if (helper(board,ind+1,row,col,block)) return true;  
            else {  
            row[i][k-1] =col[j][k-1] =block[b][k-1]=false;  
            board[i][j]='.';  
            }  
          }   
        }  
        return false;  
      }  
      else return helper(board,ind+1,row,col,block);  
    } 

X. Inefficient?
https://discuss.leetcode.com/topic/11327/straight-forward-java-solution-using-backtracking
Try 1 through 9 for each cell. The time complexity should be 9 ^ m (m represents the number of blanks to be filled in), since each blank can have 9 choices. Details see comments inside code. Let me know your suggestions.
    public void solveSudoku(char[][] board) {
        if(board == null || board.length == 0)
            return;
        solve(board);
    }
    
    public boolean solve(char[][] board){
        for(int i = 0; i < board.length; i++){
            for(int j = 0; j < board[0].length; j++){
                if(board[i][j] == '.'){
                    for(char c = '1'; c <= '9'; c++){//trial. Try 1 through 9
                        if(isValid(board, i, j, c)){
                            board[i][j] = c; //Put c for this cell
                            
                            if(solve(board))
                                return true; //If it's the solution return true
                            else
                                board[i][j] = '.'; //Otherwise go back
                        }
                    }
                    
                    return false;
                }
            }
        }
        return true;
    }
    
    private boolean isValid(char[][] board, int row, int col, char c){
        for(int i = 0; i < 9; i++) {
            if(board[i][col] != '.' && board[i][col] == c) return false; //check row
            if(board[row][i] != '.' && board[row][i] == c) return false; //check column
            if(board[3 * (row / 3) + i / 3][ 3 * (col / 3) + i % 3] != '.' && 
board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == c) return false; //check 3*3 block
        }
        return true;
    }
http://blog.csdn.net/zdavb/article/details/48165059
这道题使用的是回溯算法,回溯本质是深搜+剪枝。深搜又常常利用递归,然后当替换每个“.”时都判断是否有效。如果有效的话,就继续递归下去。
注意,一般递归函数都在开头位置判断是否结束,但是对于该问题而言,不大容易判断叶节点。所以这里采用的是利用返回值true或false来对树的深度进行控制。如果为solve到false时,就回溯。回溯的手段就是使用更改函数主体复位,并return
http://www.jiuzhang.com/solutions/sudoku-solver/
http://www.cnblogs.com/springfor/p/3884252.html
    public void solveSudoku(char[][] board){
        solve(board);
    }

    public boolean solve(char[][] board) {
        for(int i = 0; i < 9; i++) {
            for(int j = 0; j < 9; j++){
                if(board[i][j] != '.'){
                    continue;
                }
                for(int k = 1; k <= 9; k++){
                    board[i][j] = (char) (k + '0'); // set value
                    if (isValid(board, i, j) && solve(board)){
                        return true;
                    }
                    board[i][j] = '.';// backtrack
                }
                return false;//\\
            }
        }
        return true;//\\
    }
    
    
     public boolean isValid(char[][] board, int a, int b){
        Set<Character> contained = new HashSet<Character>();
        for(int j=0;j<9;j++){
            if(contained.contains(board[a][j])) return false;
            if(board[a][j]>'0' && board[a][j]<='9')
                contained.add(board[a][j]);
        }
            
        
    
        contained = new HashSet<Character>(); // or call set.clear()
        for(int j=0;j<9;j++){
            if (contained.contains(board[j][b])) {
                return false;
            }
            if (board[j][b]>'0' && board[j][b]<='9') {
                contained.add(board[j][b]);
            }
        }
        
    
        contained = new HashSet<Character>();
        for (int m = 0; m < 3; m++) {
            for (int n = 0; n < 3; n++){
                int x = a / 3 * 3 + m, y = b / 3 * 3 + n;
                if (contained.contains(board[x][y])) {
                    return false;
                }
                if (board[x][y] > '0' && board[x][y] <= '9') {
                        contained.add(board[x][y]);
                }
            } 
        }
    
        return true;
    }
http://cs-cjl.com/2016/09_29_leetcode_37_sudoku_solver
void solveSudoku(vector<vector<char>>& board) { dfs(board, 0); } bool dfs(vector<vector<char>>& board, const int pos) { if (pos == 81) { return true; } int x = pos / 9, y = pos % 9; if (board[x][y] != '.') { return dfs(board, pos + 1); } for (char i = '0'; i <= '9'; ++i) { board[x][y] = i; if (isValidSudoku(board) && dfs(board, pos + 1)) return true; } board[x][y] = '.'; return false; } bool isValidSudoku(vector<vector<char>>& board) { int col[9][9] = {0}, row[9][9] = {0}, rec[9][9] = {0}; for(int i = 0; i < 9; ++ i) { for(int j = 0; j < 9; ++ j) { if(board[i][j] != '.') { int num = board[i][j] - '0' - 1, k = i / 3 * 3 + j / 3; if(col[i][num] || row[j][num] || rec[k][num]) return false; col[i][num] = row[j][num] = rec[k][num] = 1; } } } return true; }


http://blog.csdn.net/u011095253/article/details/9158497
    public boolean isValid(int v, int row, int col, char[][] board){
        for(int i=0;i<9;i++){
            if(board[row][i] - '0'==v) return false;
            if(board[i][col] - '0'==v) return false;
            int row_s = 3*(row/3) + i/3;
            int col_s = 3*(col/3) + i%3;
            if(board[row_s][col_s] - '0'==v) return false;
        }
        return true;
    }
http://huangyawu.com/leetcode-sudoku-solver-java/
    private boolean isValid(char[][] board, int row, int col){
        for(int i=0; i<9; i++){
            if(i!=row && board[i][col] == board[row][col]) return false;
            if(i!=col && board[row][i] == board[row][col]) return false;
        }
         
        int r = row / 3 * 3;
        int c = col / 3 * 3;
        for(int i=0; i<3; i++)
            for(int j=0; j<3; j++){
                if(r + i != row && c + j != col
                        && board[r+i][c+j] == board[row][col])
                    return false;
            }
        return true;
    }
https://leetcode.com/discuss/30482/straight-forward-java-solution-using-backtracking
 Backtracking algorithms generally have exponential worst-case running time. However, the efficient pruning isValid makes it fast enough in practice :-)
public void solveSudoku(char[][] board) {
    if(board == null || board.length == 0)
        return;
    solve(board);
}
public boolean solve(char[][] board){
    for(int i = 0; i < board.length; i++){
        for(int j = 0; j < board[0].length; j++){
            if(board[i][j] == '.'){
                for(char c = '1'; c <= '9'; c++){//trial. Try 1 through 9 for each cell
                    if(isValid(board, i, j, c)){
                        board[i][j] = c; //Put c for this cell

                        if(solve(board))
                            return true; //If it's the solution return true
                        else
                            board[i][j] = '.'; //Otherwise go back
                    }
                }
                return false;
            }
        }
    }
    return true;
}
public boolean isValid(char[][] board, int i, int j, char c){
    //Check colum
    for(int row = 0; row < 9; row++)
        if(board[row][j] == c)
            return false;

    //Check row
    for(int col = 0; col < 9; col++)
        if(board[i][col] == c)
            return false;

    //Check 3 x 3 block
    for(int row = (i / 3) * 3; row < (i / 3) * 3 + 3; row++)
        for(int col = (j / 3) * 3; col < (j / 3) * 3 + 3; col++)
            if(board[row][col] == c)
                return false;
    return true;
}
https://leetcode.com/discuss/51308/two-very-simple-and-neat-java-dfs-backtracking-solutions
https://leetcode.com/discuss/7086/there-is-a-dancing-links-x-algorithm
Dr. Donald Knuth’s Dancing Links Algorithm solves an Exact Cover situation. The Exact Cover problem can be extended to a variety of applications that need to fill constraints. Sudoku is one such special case of the Exact Cover problem.
NOTE:This is a very complicate solution.
http://huntfor.iteye.com/blog/2087778
DFS在找到一个结果的时候会继续回溯寻找下一个可能的结果,因此我又设置了一个全局变量来添加控制。这无疑让代码可读性变差
// only check condition(over) at first, no need check condition before every recursive call.

Determine whether a Sudoku has a unique solution
If you return a number instead of a boolean, you can destinguish between cases where there are 0, 1, or more than 1 solution(s).
To return all solutions: clone the matrix, and put it into list.

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts