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; } }