1

题目: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.
orign_sudoku
A sudoku puzzle...
solved_sudoku

...and its solution numbers marked in red.

分析:根据数独的规则,这道题用深度优先遍历是最自然的。

要点:

  • 建立辅助变量用于快速判断一个数字是否在当前行,列和区间已经被使用了。
  • 要有二维数组转一维数组以及数组映射的思想。

    • 给出一个数字,如第56个格子(从左往右,从上往下),怎么计算出它的坐标在哪呢?
      row = 56 / 9, column = 56 % 9
    • 如一个数独游戏有九个独立的九宫格,那我们该怎么判断一个坐标(i,j)是否在某个九宫格里呢?
      请输入图片描述
  • 深度优先的递归函数最好只有一个迭代的参数,否则很容易给自己挖坑。如我只传给solve函数一个pos变量,告诉它我要处理第pos个格子。而不是传入(i, j)表示坐标。

代码:

public class Solution {
    public void solveSudoku(char[][] board) {
        rowUsed = new boolean[10][10];
        columnUsed = new boolean[10][10];
        blockUsed = new boolean[3][3][10];

        int num;
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] == '.') continue;
                num = board[i][j] - '0';
                rowUsed[i][num] = true;
                columnUsed[j][num] = true;
                blockUsed[i/3][j/3][num] = true;
            }
        }
        solve(board, 0);
    }

    private boolean solve(char[][] board, int pos) {
        int row = pos / 9;
        int column = pos % 9;

        // looks we have already finish the board
        if (pos > 80) return true;

        if (board[row][column] != '.') {
            return solve(board, pos+1);
        }
        for (int num = 1; num < 10; num++) {
            if (rowUsed[row][num] || columnUsed[column][num] || blockUsed[row/3][column/3][num]) continue;
            rowUsed[row][num] = columnUsed[column][num] = blockUsed[row/3][column/3][num] = true;
            board[row][column] = (char)('0' + num);
            if (solve(board, pos + 1)) {
                return true;//if get the valid solution, don't go further
            } else {
                board[row][column] = '.';
                rowUsed[row][num] = columnUsed[column][num] = blockUsed[row/3][column/3][num] = false;
            }
        }
        return false;
    }

    private boolean[][] rowUsed;
    private boolean[][] columnUsed;
    private boolean[][][] blockUsed;
}

ssnau
1.5k 声望98 粉丝

负能量职业打码师


引用和评论

0 条评论