LeetCode037——解数独

版权声明:版权所有,转载请注明原网址链接。 https://blog.csdn.net/qq_41231926/article/details/81660151

原题链接:https://leetcode-cn.com/problems/sudoku-solver/description/

题目描述:

知识点:递归,回溯

基本思路:

(1)新建一个成员变量retBoard,该成员变量是一个char类型的二维数组,数组维数是9 × 9的。新建一个内部类Point,该类有两个成员变量i和j,分别记录点的横、纵坐标,并有一个带参数的构造方法可以给i和j变量赋初值。

(2)遍历整个九宫格,寻找到其中内容为'.'的点,并将其坐标作为参数新建一个Point类型的对象将其加入到一个ArrayList<Point>类型的数组arrayList中,该数组用以记录需要填充的格子的点。

(3)调用函数fillNumber(char[][] board, ArrayList<Point> arrayList, int index)来给arrayList的第index个点赋值。在该函数中,递归地为整张九宫格中的'.'填充新的数字。

a.如果index == arrayList.size(),我们用retBoard数组记录下board数组中各个元素的值,并返回。

b.遍历数字1 - 9,如果arrayList中第index个点的坐标所对应的位置可以填充,就修改board对应位置的值,并尝试着递归地调用fillNumber函数填充下一个点。注意在递归调用之后,如果该方向是错误的,需要注意函数回溯过程时变量的回溯,需要将board对应位置的值重新置为'.'。

JAVA代码:

public class Solution {
	
	private char[][] retBoard = new char[9][9];
	
	private class Point {
		int i;
		int j;
		
		public Point(int i, int j) {
			this.i = i;
			this.j = j;
		}
	}

	public void solveSudoku(char[][] board) {
		//在arrayList中保存需要填充的空格的横坐标和纵坐标
		ArrayList<Point> arrayList = new ArrayList<>();		
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				if(board[i][j] == '.')
					arrayList.add(new Point(i, j));
			}
		}
		fillNumber(board, arrayList, 0);
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				board[i][j] = retBoard[i][j];
			}
		}
	}

	//将要给arrayList中的第index个点进行填充值
	private void fillNumber(char[][] board, ArrayList<Point> arrayList, int index) {
		if(index == arrayList.size()) {
			for (int i = 0; i < 9; i++) {
				for (int j = 0; j < 9; j++) {
					retBoard[i][j] = board[i][j];
				}
			}
			return;
		}
		int indexi = arrayList.get(index).i;
		int indexj = arrayList.get(index).j;
		for (int num = 1; num <= 9; num++) {
			if(canFillThisNum(board, indexi, indexj, num)) {
				board[indexi][indexj] = String.valueOf(num).charAt(0);
				fillNumber(board, arrayList, index + 1);
				board[indexi][indexj] = '.';
			}
		}
	}
	
	private boolean canFillThisNum(char[][] board, int i, int j, int num) {
		if(board[i][j] != '.') {
			return false;
		}
		HashSet<Character> hashSet = new HashSet<>();
		for (int k = 0; k < 9; k++) {
			if(board[i][k] != '.') {
				hashSet.add(board[i][k]);
			}
			if(board[k][j] != '.') {
				hashSet.add(board[k][j]);
			}
		}
		if(area(i, j) == 1) {
			for (int k = 0; k <= 2; k++) {
				for (int p = 0; p <= 2; p++) {
					if(board[k][p] != '.') {
						hashSet.add(board[k][p]);
					}
				}
			}
		}else if(area(i, j) == 2) {
			for (int k = 0; k <= 2; k++) {
				for (int p = 3; p <= 5; p++) {
					if(board[k][p] != '.') {
						hashSet.add(board[k][p]);
					}
				}
			}
		}else if(area(i, j) == 3) {
			for (int k = 0; k <= 2; k++) {
				for (int p = 6; p <= 8; p++) {
					if(board[k][p] != '.') {
						hashSet.add(board[k][p]);
					}
				}
			}
		}else if(area(i, j) == 4) {
			for (int k = 3; k <= 5; k++) {
				for (int p = 0; p <= 2; p++) {
					if(board[k][p] != '.') {
						hashSet.add(board[k][p]);
					}
				}
			}
		}else if(area(i, j) == 5) {
			for (int k = 3; k <= 5; k++) {
				for (int p = 3; p <= 5; p++) {
					if(board[k][p] != '.') {
						hashSet.add(board[k][p]);
					}
				}
			}
		}else if(area(i, j) == 6) {
			for (int k = 3; k <= 5; k++) {
				for (int p = 6; p <= 8; p++) {
					if(board[k][p] != '.') {
						hashSet.add(board[k][p]);
					}
				}
			}
		}else if(area(i, j) == 7) {
			for (int k = 6; k <= 8; k++) {
				for (int p = 0; p <= 2; p++) {
					if(board[k][p] != '.') {
						hashSet.add(board[k][p]);
					}
				}
			}
		}else if(area(i, j) == 8) {
			for (int k = 6; k <= 8; k++) {
				for (int p = 3; p <= 5; p++) {
					if(board[k][p] != '.') {
						hashSet.add(board[k][p]);
					}
				}
			}
		}else if(area(i, j) == 9) {
			for (int k = 6; k <= 8; k++) {
				for (int p = 6; p <= 8; p++) {
					if(board[k][p] != '.') {
						hashSet.add(board[k][p]);
					}
				}
			}
		}
		if(hashSet.contains(String.valueOf(num).charAt(0))) {
			return false;
		}
		return true;
	}

	private int area(int i, int j) {
		if(i >= 0 && i <= 2 && j >= 0 && j <= 2) {
			return 1;
		}else if(i >= 0 && i <= 2 && j >= 3 && j <= 5) {
			return 2;
		}else if(i >= 0 && i <= 2 && j >= 6 && j <= 8) {
			return 3;
		}else if(i >= 3 && i <= 5 && j >= 0 && j <= 2) {
			return 4;
		}else if(i >= 3 && i <= 5 && j >= 3 && j <= 5) {
			return 5;
		}else if(i >= 3 && i <= 5 && j >= 6 && j <= 8) {
			return 6;
		}else if(i >= 6 && i <= 8 && j >= 0 && j <= 2) {
			return 7;
		}else if(i >= 6 && i <= 8 && j >= 3 && j <= 5) {
			return 8;
		}else if(i >= 6 && i <= 8 && j >= 6 && j <= 8) {
			return 9;
		}
		return -1;
	}

	public static void main(String[] args) {
		String[][] stringBoard = {{"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"}};
		char[][] board = new char[9][9];
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				board[i][j] = stringBoard[i][j].charAt(0);
			}
		}
		
		System.out.println("做题前:");
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				System.out.print(board[i][j] + " ");
			}
			System.out.println();
		}
		new Solution().solveSudoku(board);
		System.out.println("做题后:");
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				System.out.print(board[i][j] + " ");
			}
			System.out.println();
		}
	}

}

复杂度分析:

时间复杂度:因为需要递归调用函数n次,每次递归调用最多有9个方向可以走,所以时间复杂度为O(9  ^ n),其中n为九宫格中'.'的数量。

空间复杂度:因为需要递归调用函数n次,所以空间复杂度为O(n)

猜你喜欢

转载自blog.csdn.net/qq_41231926/article/details/81660151