題目描述:
https://leetcode.com/problems/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:
- Each of the digits
1-9
must occur exactly once in each row. - Each of the digits
1-9
must occur exactly once in each column. - Each of the the digits
1-9
must occur exactly once in each of the 93x3
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
.
解答:
package com.jack.algorithm;
/**
* create by jack 2019/6/30
*
* @author jack
* @date: 2019/6/30 10:14
* @Description:
* 使用數字字符1-9填充二維數組
*/
public class SudokuSolver {
/**
* 37-題目描述:
* https://leetcode.com/problems/sudoku-solver/
*
* @param board
*/
public static void solveSudoku(char[][] board) {
if (solve(board));
}
/**
* 判斷某一行是否已經存在字符num,存在返回true,不存在返回false
* @param board
* @param row
* @param num
* @return
*/
private static boolean usedRow(char[][] board, int row, char num) {
//i小於二維數組的列數
for (int i = 0; i < board[0].length; i++) {
if (board[row][i] == num) {
return true;
}
}
return false;
}
/**
* 判斷num這個字符是否在這一列被使用了,被使用了返回true,沒被使用返回false
* @param board
* @param col
* @param num
* @return
*/
private static boolean usedCol(char[][] board, int col, char num){
for(int i=0; i<board.length; i++) {
if (board[i][col] == num) {
return true;
}
}
return false;
}
/**
* 判斷3*3的單元格是否存在字符num,存在返回true,不存在返回false
* @param board
* @param rowStart
* @param colStart
* @param num
* @return
*/
private static boolean usedBox(char[][] board, int rowStart, int colStart, char num) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i + rowStart][j + colStart] == num) {
return true;
}
}
}
return false;
}
/**
* row行,collie填充字符num,是否安全
* @param board
* @param row
* @param col
* @param num
* @return
*/
private static boolean isSafe(char[][] board, int row, int col, char num) {
//row-row%3用的比較巧妙,根據傳入的row找到第0,3,6行,這是3*3行的起始行
//同理col-col%3,根據傳入的col找到0,3,6列,這是3*3行的起始列
//所以根據上面的計算,可以找到所有的3*3的起始單元格
return !usedRow(board, row, num) && !usedCol(board, col, num) && !usedBox(board, row - row % 3, col - col % 3, num) && board[row][col] == '.';
}
/**
*查找到二維數組中有"."的列,並返回一個數組,數組兩個值,第一個值是i表示行,第二個值是j表示列
* @param board
* @return
*/
private static int[] getUnfilledCell(char[][] board) {
//二維數組行的長度
for (int i = 0; i < board.length; i++) {
//二維數組的列數
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] == '.') {
return new int[]{i, j};
}
}
}
return null;
}
/**
* 遞歸調用填充,把“.”填充爲字符1-9
* @param board
* @return
*/
private static boolean solve(char[][] board) {
//獲取到沒有填充的單元格所在的行和列的數組,如果返回null表示已經填充完成了,直接返回ture
int[] next = getUnfilledCell(board);
if (next == null) {
return true;
}
//獲取沒有填充列的行號,列號
int row = next[0], col = next[1];
//從ascill字符遍歷字符1-9字符
for (char i = '1'; i <= '9'; i++) {
//判斷填充字符i(i表示字符1-9),是否安全,如果安全,則把i賦值給row,col單元格
if (isSafe(board, row, col, i)) {
board[row][col] = i;
//上面賦值了一個元素,繼續對第二個"."進行賦值,繼續遞歸調用,如果解決了就返回true,沒解決就重新把row,col單元格賦值爲"."
if (solve(board)) {
return true;
}
board[row][col] = '.';
}
}
return false;
}
public static void main(String[] args) {
}
}
源碼: