理论上 使用回溯方法,起点终点和方向是确定的,那么解决问题的过程和结果就是唯一的(栈的压入与弹出的顺序也是固定的)
此文章主要解决leetcode上的解数独题,这题也不知道怎么为啥非要用char[][]数组,多余的操作多了些,代码量稍微多了些
输出为 记录栈的压入弹出记录 和最终结果
注意此代码并不能判断所给数独是否有解
import java.util.Objects;
import java.util.Stack;
class Solution {
class Point {
int row;
int col;
int value;
Point(int row, int col) {
super();
this.row = row;
this.col = col;
this.value = 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Point point = (Point) o;
return row == point.row && col == point.col;
}
@Override
public int hashCode() {
return Objects.hash(row, col);
}
@Override
public String toString() {
return "Point{" +
"row=" + row +
", col=" + col +
", value=" + value +
'}';
}
}
private int[][] intArrays = new int[9][9];
private char[][] charArrays={
{'5','3','.','.','7','.','.','.','.'},
{'6','.','.','1','9','5','.','.','.'},
{'.','9','8','.','.','.','.','6','.'},
{'8','.','.','.','6','.','.','.','3'},
{'4','.','.','8','.','3','.','.','1'},
{'7','.','.','.','2','.','.','.','6'},
{'.','6','.','.','.','.','2','8','.'},
{'.','.','.','4','1','9','.','.','5'},
{'.','.','.','.','8','.','.','7','9'}};
private int[][] remainingRows = new int[9][9];
private int[][] remainingColumns = new int[9][9];
private int[][] remainingGrids = new int[9][9];
private int numEmpty = 0;
Stack<Point> stack = new Stack<>();
/*
初始化信息
intArrays 实际操作的二维数组
charArrays char数组
remainingRows 行剩余数 每行 存储行剩余 故位置为i,j小格子 对应i行
remainingColumns 列剩余数 每行 存储列剩余 故位置为i,j小格子 对应j行
remainingGrids 九宫格剩余数 每行 存储列剩余 故位置为i,j小格子 对应i/3*3+j/3行(对应所在九宫格中序号i/3*3+j/3)
numEmpty 剩余未填数
*/
public void initial() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
remainingRows[i][j] = j+1;
remainingColumns[i][j] = j+1;
remainingGrids[i][j] = j+1;
}
}
}
/*
char数组转为int数组 和信息扫描 信息存入remainings中
*/
public void convertToIntArrays() {
initial();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (charArrays[i][j] != '.') { //此处有数字
int num = charArrays[i][j] - 48;
intArrays[i][j] = num;
remainingRows[i][num-1] = 0;
remainingColumns[j][num-1] = 0;
remainingGrids[i / 3 * 3 + j / 3][num-1] = 0;
} else {
numEmpty++;
}
}
}
}
/*
int数组转为char数组
*/
public void convertToCharArrays() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
charArrays[i][j] = (char) (intArrays[i][j] + 48);
}
}
}
/*
解决问题的主体
*/
public void solve() {
/*
找到一个起始位置
该位置为空
给出一个合适的值
如果无法给出合适的值
那么就要弹出一个值
*/
Point currentP; //目前需要赋值的点
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; ) {
if (intArrays[i][j] == 0) { //需要填空
currentP=new Point(i, j);
if(!stack.isEmpty()&&stack.peek().equals(currentP)){
currentP=stack.pop();
++numEmpty;
System.out.println("弹出 "+currentP.toString()+" 剩余"+numEmpty);
}
currentP.value = generateValue(currentP);
if (currentP.value != -1) {
stack.push(currentP);
--numEmpty;
System.out.println("压入 "+currentP.toString()+" 剩余"+numEmpty);
j++;
if (numEmpty == 0) {
return;
}
} else {
i=stack.peek().row;
j=stack.peek().col;
}
}else {
j++;
}
}
}
//将栈中的点放入intArrays中
}
public int generateValue(Point currentP) {
//根据当前P点的value值,提供一个合适的新值,同时,remainings中的值更新
int row = currentP.row;
int col = currentP.col;
int value = currentP.value;
//如果value的值不等于0,说明之前remaings给出值不合适,要还回去
if(value!=0){
remainingRows[row][value-1] =value;
remainingColumns[col][value-1] =value;
remainingGrids[row / 3 * 3 + col / 3][value-1] =value;
}
//value的值应该保证小于10
while (value < 9) {
++value;
//如果在remainingS中都还有这个数,那么就可以使用,即可保证各行各列和各九宫格不会重复,故无需查重
if (remainingRows[row][value-1] == value && remainingColumns[col][value-1] == value &&
remainingGrids[row / 3 * 3 + col / 3][value-1] == value){
remainingRows[row][value-1] =0;
remainingColumns[col][value-1] =0;
remainingGrids[row / 3 * 3 + col / 3][value-1] =0;
return value;
}
}
//此处如果超过10 说明所有的值都不合适 应该进行回溯 那么赋予的值也应该撤回
return -1;
}
public void writeToIntArrays(){
for(Point p:stack){
intArrays[p.row][p.col]=p.value;
}
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
System.out.print(intArrays[i][j]);
}
System.out.println();
}
}
public void solveSudoku() {
convertToIntArrays();
solve();
writeToIntArrays();
convertToCharArrays();
}
public static void main(String[] args) {
Solution s=new Solution();
s.solveSudoku();
}
}