1. 程式人生 > >Leetcode 37 Sudoku Solver

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

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.

這個題為Leetcode 36 的變形,在原有的基礎上加上了回溯的方法,主流的方法是使用dfs

1)

class Solution{
    
     public void solveSudoku(char[][] board) {
		Set<Character>[] rows = new HashSet[9];
		Set<Character>[] columns = new HashSet[9];
		Set<Character>[][] boards = new HashSet[3][3];
		for(int i=0; i<9; i++){
			rows[i]=new HashSet<>();
			columns[i]=new HashSet<>();
		}
		for(int i=0; i<3; i++){
			for(int j=0; j<3; j++){
				boards[i][j]=new HashSet<>();
			}
		}  
		int left=0;
		for(int i=0; i<9; i++){
			for(int j=0; j<9; j++){
				if(board[i][j]=='.') {left++; continue;}  //count empty cells
				rows[i].add(board[i][j]); //records all available chars in rows
				columns[j].add(board[i][j]); //records all available chars in columns
				boards[i/3][j/3].add(board[i][j]); //records all available chars in each sub Board
			} 
		} 
		dfs(rows,columns,boards,board,left); 
    }
	boolean dfs(Set<Character>[] rows, Set<Character>[] columns, Set<Character>[][] boards,char[][] board, int count){			   
			if(count==0) return true; // once count==0 you filled all the empty cells
			for(int i=0; i<9; i++){
				for(int j=0; j<9; j++){	
					if(board[i][j]!='.') continue; 
					for(char digit='1'; digit<='9'; digit++){
						if(!rows[i].contains(digit) && !columns[j].contains(digit) && !boards[i/3][j/3].contains(digit)){ // if the character does not exist in this row, column and sub board continue
							board[i][j]=digit;
							rows[i].add(digit); columns[j].add(digit); boards[i/3][j/3].add(digit);
							if(dfs(rows,columns,boards,board,count-1)) return true;	// count-1 is number of empty cells left
							rows[i].remove(digit); columns[j].remove(digit); boards[i/3][j/3].remove(digit); 
							board[i][j]='.';
						}
					} 
					if(board[i][j]=='.') return false;
				}
			}
			return false;
	}
}

2)

class Solution {
    class Position {
        int x, y;
        int v;
        Position(int x, int y, int  v){
            this.x = x;
            this.y = y;
            this.v = v;
        }
    }
    public void solveSudoku(char[][] board) {            
        int[][] states = new int[9][];
        int i,j,v;
        
        List<Position> values = new ArrayList<Position>(81);
        for(i=0; i<9; i++){
            states[i] = new int[9];
            for(j=0; j<9; j++){
                if(board[i][j] !='.'){
                    v = 1 << (board[i][j] - '0' - 1);
                    states[i][j] = v ^ 0x01FF;
                    values.add(new Position(i, j, v));
                }
            }
        }
        
        solve(states, values);
        for(i=0; i<9; i++){
            for(j=0; j<9; j++){
                if(board[i][j] == '.'){
                    board[i][j] = bit2Char(states[i][j]);
                }
            }
        }
    }
    
    boolean solve(int[][] states, List<Position> values){
        
        while(!values.isEmpty()){
            Position pos = values.remove(values.size() -1);
            int br = pos.x/3*3, bc = pos.y/3*3;
            boolean b;
            for(int k=0; k<9; k++) {
                if(k != pos.y) {
                    b = setBit(states, pos.x, k, pos.v, values);
                    if(!b) {
                        values.clear();
                        return false;
                    }
                }
                if(k != pos.x) {
                    b = setBit(states, k, pos.y, pos.v, values);
                    if(!b) {
                        values.clear();
                        return false;
                    }
                }
                if((br+k/3) != pos.x && (br+k%3) != pos.y){
                    b = setBit(states, br + k/3,  bc + k%3, pos.v, values);
                    if(!b) {
                        values.clear();
                        return false;
                    }
                }
            }
        }
        
        int leastx = -1, leasty = -1, least = 0;
        for(int i=0; i<9; i++){
            for(int j=0; j<9; j++){
                int bcnt = bitCount(states[i][j]);
                if(bcnt!=8 && bcnt > least) {
                    leastx = i;
                    leasty = j;
                    least = bcnt;
                }
            }
        }
        
        if(least != 0){
            int i;
            int[][] statesClone = new int[9][];
            for(i=0; i<9; i++){
                statesClone[i] = new int[9];
            }
            
            int t= states[leastx][leasty] ^ 0x01FF, s;
            while(t>0){
                copyArray(states, statesClone);
                s = t;
                t &= (t-1);
                s ^= t;
                statesClone[leastx][leasty] = s ^ 0x01FF;
                values.add(new Position(leastx, leasty, s)); 
                if(solve(statesClone, values)) {
                    copyArray(statesClone, states);
                    return true;
                }              
            }
            return false;
        } else {
            return true;
        }
    }
    
    boolean setBit(int[][] states, int i, int j , int v,  List<Position> values){
        if(bitCount(states[i][j]) == 8){  // conflict happening if existed
            return (states[i][j] & v) != 0;
        }else {
            states[i][j] |= v;
            if(bitCount(states[i][j]) == 8){
                int nv = states[i][j] ^ 0x01FF;  // change 1 to 0, 0 to 1 in the last 8 bits;
                values.add(new Position(i, j, nv));
            }
            return true;
        }
    }
                   
    void copyArray(int[][] src, int[][] dest){
        for(int i=0; i<9; i++){
           System.arraycopy(src[i], 0, dest[i], 0, 9);
        }
    }
    
    int bitCount(int n){
        int count = 0;
        while (n>0) {
            n &= (n -1) ;
            ++count;
        }
        return count;
    }
    
    char bit2Char(int bits){
        int i = 0;
        for(; i<9 && ((1<<i)&bits)!=0; i++);
        return (char)(i+1+'0');
    }
                        
}