Sudoku Solver

https://leetcode.com/problems/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.

解题思路:

这道题要求可能的解,可以想到用回溯。但是题目讲到,可能的解只有一个,我们只需要把这一个求出来就可以了。

1. 这里我们用了三个set数组,分别记录每行、每列和每个3*3的小格子里已经有的数组。这样,新选择的数字就不能和它们重复。这三组set用来作为递归的剪枝条件。

2. 原来的board是二维的,这里我仍然使用大多数dfs方法中常用的step变量来计数。这样就要算和step对应的行数、列数,以及3*3的小格子的index。

3. 也是最关键的。本题要找到的是唯一的解,而且要求回写到board中的。这样dfs函数就不能是void了。为什么?因为void一般是有另一个变量记录所有可能的解,不断的递归、回溯的同时,将解塞进这个变量里。最后看这个变量的内容即可。但是这里,board是同时要回溯的。如果void,找到可能的解后,dfs还是要回溯。这样,整个方法递归完成,board无论如何是要回到原样的。也就是说,做了半天等于没做。

那么,如何解决?

我们这里用了一个比较通用的方法,也是以后遇到这类问题可以采用的方法。就是将dfs的返回值改为boolean。如果dfs的返回值为true,也就是说是一个可能的解,那么就不用回溯了,否则才回溯。这样,找到一个可能的解,就直接返回true了,递归也不会再进行下去。于是,board就可以保留唯一的解的状态,直接返回。

public class Solution {

    public void solveSudoku(char[][] board) {

        Set<Character>[] rowSet = new HashSet[board.length];

        Set<Character>[] columnSet = new HashSet[board.length];

        Set<Character>[] squareSet = new HashSet[(board.length / 3) * (board.length / 3)];

        //初始化行set、列set和小squareSet

        for(int i = 0; i < board.length; i++) {

            rowSet[i] = new HashSet<Character>();

            for(int j = 0; j < board.length; j++) {

                if(i == 0) {

                    columnSet[j] = new HashSet<Character>();

                }

                

                int squareIndex = (i / 3) * (board.length / 3) + (j / 3);

                if(squareSet[squareIndex] == null) {

                    squareSet[squareIndex] = new HashSet<Character>(); 

                }

                if(board[i][j] != '.') {

                    rowSet[i].add(board[i][j]);

                    columnSet[j].add(board[i][j]);

                    squareSet[squareIndex].add(board[i][j]);

                }

            }

        }

        dfs(board, rowSet, columnSet, squareSet, 0);

    }

    

    public boolean dfs(char[][] board, Set<Character>[] rowSet, Set<Character>[] columnSet, Set<Character>[] squareSet, int step) {

        if(step == board.length * board.length) {

            return true;

        }

        int row = step / board.length;

        int column = step % board.length;

        int squareIndex = (row / 3) * (board.length / 3) + (column / 3);

        if(board[row][column] != '.') {

            return dfs(board, rowSet, columnSet, squareSet, step + 1);

        } else {

            for(int i = 1; i < 10; i++) {

                char temp = (char)('0' + i);

                if(!rowSet[row].contains(temp) && !columnSet[column].contains(temp) && !squareSet[squareIndex].contains(temp)) {

                    board[row][column] = temp;

                    rowSet[row].add(temp);

                    columnSet[column].add(temp);

                    squareSet[squareIndex].add(temp);

                    if(dfs(board, rowSet, columnSet, squareSet, step + 1)) {

                        return true;

                    }

                    board[row][column]= '.';

                    rowSet[row].remove(temp);

                    columnSet[column].remove(temp);

                    squareSet[squareIndex].remove(temp);

                }

            }

        }

        return false;

    }

}

 

你可能感兴趣的:(sudo)