37. 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.

 

 

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        def backtrack(board: List[List[str]], i: int, j: int) -> bool:
      
            if j == 9:
                # 穷举到最后一列的话就换到下一行重新开始。
                return backtrack(board, i + 1, 0)
            if i == 9:
                # 找到一个可行解,触发 base case
                return True

            if board[i][j] != '.':
                # 如果有预设数字,不用我们穷举
                return backtrack(board, i, j + 1)

            for ch in range(1,10):
                ch = str(ch)
                # 如果遇到不合法的数字,就跳过
                if is_vaild(board, i, j, ch):

                    board[i][j] = ch
                    # 如果找到一个可行解,立即结束
                    if backtrack(board, i, j + 1):
                        return True
                    board[i][j] = '.'
            # 穷举完 1~9,依然没有找到可行解,此路不通
            return False




        def is_vaild(board,i,j,val):
            for a in range(9):
                if board[i][a] == val:
                    return False
            for a in range(9):
                if board[a][j] == val:
                    return False
            ki = i//3 * 3
            kj = j//3 * 3
            for a in range(3):
                for b in range(3):
                    if board[ki+a][kj+b] == val:
                        return False
            return True
        backtrack(board,0,0)
                

 

 

 

 

怎么做二维递归呢?

本题就不一样了,本题中棋盘的每一个位置都要放一个数字,并检查数字是否合法,解数独的树形结构要比N皇后更宽更深。

N  皇后 只要判断放不放东西。数独需要考虑放哪个数字。

 

 

class Solution {
public:
    bool backtrack(vector<vector<char>>& board) {
        for(int level = 0; level < board.size(); ++level) {
            for (int index = 0; index < board[0].size();++index) {
                if (board[level][index] != '.') continue;
                for (char val = '1';val <='9';val++) {
                    if(valid(board,level,index,val)) {
                        board[level][index] = val;
                        if(backtrack(board)) return true;
                        board[level][index] = '.';
                    }
                }
                return false;
            }
        }
        return true;
    }

    bool valid(vector<vector<char>>& board, int level, int index, char val) {
        // 检查列
        for(int i = 0; i < 9 ;++i) {
            if (board[i][index] == val ) {
                return false;
            }
        }
        // 检查行
        for (int i = 0;i < 9; ++i) {
            if (board[level][i] == val) {
                return false;
            }
        }
        // 检查小方格
        int start_level = (level /3) *3;
        int start_index = (index /3) *3;
        for(int i = start_level; i < start_level+3;++i ) {
            for(int j = start_index; j <start_index+3;++j) {
                if (board[i][j] == val) {
                    return false;
                }
            }
        }
        return true;
    }


    void solveSudoku(vector<vector<char>>& board) {
        backtrack(board);
    }
};

 

 

 

 

如果当前位置是空,则尝试1到9中所有的数字,如果对于1到9中的某些数字,当前是合法的,则继续尝试下一个位置(调用自身)。

 

 1 public class Solution {
 2     public void solveSudoku(char[][] board) {
 3         if(board == null || board.length == 0)
 4             return;
 5         solve(board);
 6     }
 7     
 8     public boolean solve(char[][] board){
 9         for(int i = 0; i < board.length; i++){
10             for(int j = 0; j < board[0].length; j++){
11                 if(board[i][j] == '.'){
12                     for(char c = '1'; c <= '9'; c++){//trial. Try 1 through 9
13                         if(isValid(board, i, j, c)){
14                             board[i][j] = c; //Put c for this cell
15                             
16                             if(solve(board))
17                                 return true; //If it's the solution return true
18                             else
19                                 board[i][j] = '.'; //Otherwise go back
20                         }
21                     }
22                     
23                     return false;
24                 }
25             }
26         }
27         return true;
28     }
29     
30     private boolean isValid(char[][] board, int row, int col, char c){
31         for(int i = 0; i < 9; i++) {
32             if(board[i][col] != '.' && board[i][col] == c) return false; //check row
33             if(board[row][i] != '.' && board[row][i] == c) return false; //check column
34         }
35         for(int i = 3*(row/3);i<3*(row/3+1);i++)
36             for(int j = 3*(col/3);j<3*(col/3+1);j++)
37             if(board[i][j] != '.' && board[i][j] == c) return false; //check 3*3 block
38         
39         return true;
40     }
41 }

 

posted @ 2018-04-23 10:39  乐乐章  阅读(327)  评论(0编辑  收藏  举报