36. 有效的数独(超级详细)(判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可) (特别详解)

####题目描述:

	判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字
	是否有效即可。
	1.数字 1-9 在每一行只能出现一次。
	2.数字 1-9 在每一列只能出现一次。
	3.数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

要弄清楚这个问题,就是要知道验证的算法是什么.

  • 1.验证每一行上面是否出现了重复的数字(1-9)
  • 2.验证每一列上是否出现了重复的数字
  • 3.验证每一个宫上面是否出现了重复的数字,

也就是说我们,要在两次循环(一次外循环,一次内循环)中进行这三次验证.

前提(如何去验证是否存在重复的数字?)

验证的方法就是使用数组,你想一下,总共9个数字,你在验证这个数字在行里面是否
已经出现了,你构建一个数组,长度为10,专门用来验证行的,假设验证的当前数字是5,
那么你就在这个数组里面索引为5的位置设置为1(代表出现过了),如果在验证当前行
时,别的列还出现了5,那么你判断这个数组索引为4的位置是否为1,如果是1,代表重复,
直接返回

还有一个需要强调的问题,就是如果只是使用两次循环的话,本来就只能够验证81个
数,只能验证9行中每一行是否有重复的数据.
但是现在要做的同时要验证3处,行是否重复,列是否重复,宫是否重复.
每一次验证,能得到的是坐标(i跟j),

只有一个坐标(i,j)要验证三处:


问题的解决:

  • 验证行当前坐标的值是否在当前行里面重复出现过了.
for(int i = 0; i < 9; i++) {
		int[] row = new int[9];
		for(int j = 0; j < 9; j++) {
			if(board[i][j] != '.') {  // 当前的坐标是验证行的
		if(row[board[i][j] - '1'] == 1) {
			return false;	
		} else {
			row[board[i][j] - '1'] = 1;
		}
	}
}

循环到了(i,j)坐标,先获取这个值board[i][j],看一下这个值是否为'.',
先假设为6,开始时row这个数组的9个位置全是0,所以就会走
	row[board[i][j] - '1'] = 1;
这段代码,然后数组的就变成了
	[0, 0, 0, 0, 0, 1, 0, 0, 0]    --- 这个数组此时的意义就是,当前行
	存在6,因为索引为5的位置是1,代表6数字曾经在这一行出现过了.

注意这个数组是定义在这个内循环之外,外循环值内的,也就是说,当i为2时,换了一
行之后,就需要重新初始化.

需要注意的一点:
当在遍历第一行的数据是,(i,j)i的坐标全为0,说明是同一行,如果把i跟j的位置变换一下
变成(j,i),那么i都是0,也就是说,变成了一列了,列的数字都是0,

  • 验证当前的左边在这一列是否存在重复的元素
for(int i = 0; i < 9; i++){
	int[] col = new int[9];
	for(int j = 0; j < 9; j++) {
		// 验证当前坐标的反置位置的元素是否在它的这一列存曾经出现过
		if(board[j][i] != '.') {  // 左边变成(j,i),就是验证列了  
			// 因为在这一次循环中,i都是不变的,变得都是j
			if(col[board[j][i] - '1'] == 1) {
				return false;
			} else {
				col[board[j][i] - '1'] = 1;
			}
		}
	}
	// 在这个外循环里面,每一次变得都是j,
}

假设i = 2,说明遍历到了这个二维数组的第三行了,当吧左边反过来,也就是说这
一次遍历第2行元素时,列都是2,就变成了,这些元素都是第三列元素了,所以就可以
进行列上面的判断是否出现重复了.

  • 验证当前元素在一个宫里面是否曾经出现过.

在解决这个问题之前,先看一个东西,宫是如何确定的.
36. 有效的数独(超级详细)(判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可) (特别详解)_第1张图片

现在需要分析的问题是:
现在假设遍历到了第三行数据,当你遍历第三行第一个数是,你需要将这个左边(2,0)
坐标转换,转换成,遍历当前行,的当前列的元素时,需要查询到这个坐标的数字,所在的宫的所有的元素.

看这个坐标转换的算法:

@Test
	public void test01() {
		for(int i = 0; i < 9; i++) {
			for(int j = 0; j < 9; j++) {
				int cubeX = 3 * (i/3) + j/3;
				int cubeY = 3 * (i%3) + j%3;
				System.out.println("cubeX: " + cubeX  + "-   cubeY:" + cubeY);
			}
			System.out.println("----------------");
		}
	}

打印的结果:

cubeX: 0-   cubeY:0
cubeX: 0-   cubeY:1
cubeX: 0-   cubeY:2
cubeX: 1-   cubeY:0
cubeX: 1-   cubeY:1
cubeX: 1-   cubeY:2
cubeX: 2-   cubeY:0
cubeX: 2-   cubeY:1
cubeX: 2-   cubeY:2
----------------
cubeX: 0-   cubeY:3
cubeX: 0-   cubeY:4
cubeX: 0-   cubeY:5
cubeX: 1-   cubeY:3
cubeX: 1-   cubeY:4
cubeX: 1-   cubeY:5
cubeX: 2-   cubeY:3
cubeX: 2-   cubeY:4
cubeX: 2-   cubeY:5
----------------
cubeX: 0-   cubeY:6
cubeX: 0-   cubeY:7
cubeX: 0-   cubeY:8
cubeX: 1-   cubeY:6
cubeX: 1-   cubeY:7
cubeX: 1-   cubeY:8
cubeX: 2-   cubeY:6
cubeX: 2-   cubeY:7
cubeX: 2-   cubeY:8
----------------
cubeX: 3-   cubeY:0
cubeX: 3-   cubeY:1
cubeX: 3-   cubeY:2
cubeX: 4-   cubeY:0
cubeX: 4-   cubeY:1
cubeX: 4-   cubeY:2
cubeX: 5-   cubeY:0
cubeX: 5-   cubeY:1
cubeX: 5-   cubeY:2
----------------
cubeX: 3-   cubeY:3
cubeX: 3-   cubeY:4
cubeX: 3-   cubeY:5
cubeX: 4-   cubeY:3
cubeX: 4-   cubeY:4
cubeX: 4-   cubeY:5
cubeX: 5-   cubeY:3
cubeX: 5-   cubeY:4
cubeX: 5-   cubeY:5
----------------
cubeX: 3-   cubeY:6
cubeX: 3-   cubeY:7
cubeX: 3-   cubeY:8
cubeX: 4-   cubeY:6
cubeX: 4-   cubeY:7
cubeX: 4-   cubeY:8
cubeX: 5-   cubeY:6
cubeX: 5-   cubeY:7
cubeX: 5-   cubeY:8
----------------
cubeX: 6-   cubeY:0
cubeX: 6-   cubeY:1
cubeX: 6-   cubeY:2
cubeX: 7-   cubeY:0
cubeX: 7-   cubeY:1
cubeX: 7-   cubeY:2
cubeX: 8-   cubeY:0
cubeX: 8-   cubeY:1
cubeX: 8-   cubeY:2
----------------
cubeX: 6-   cubeY:3
cubeX: 6-   cubeY:4
cubeX: 6-   cubeY:5
cubeX: 7-   cubeY:3
cubeX: 7-   cubeY:4
cubeX: 7-   cubeY:5
cubeX: 8-   cubeY:3
cubeX: 8-   cubeY:4
cubeX: 8-   cubeY:5
----------------
cubeX: 6-   cubeY:6
cubeX: 6-   cubeY:7
cubeX: 6-   cubeY:8
cubeX: 7-   cubeY:6
cubeX: 7-   cubeY:7
cubeX: 7-   cubeY:8
cubeX: 8-   cubeY:6
cubeX: 8-   cubeY:7
cubeX: 8-   cubeY:8
----------------

分析:

当循环走到i=2时,遍历到的是第三行的数据 
当 i = 2 , j = 0时   cubeX: 0-   cubeY:6 
这个坐标是第三宫(宫二)的第一个元素(0,6)
当 i = 2 , j = 1时   cubeX: 0-   cubeY:7
这个坐标是第三宫(宫二)的第二个元素(0,7)
当 i = 2, j = 2时    cubeX: 0-   cubeY:8
这个坐标是第三宫(宫二)的第三个元素(0,8)
当 i = 2 , j = 3时   cubeX: 1-   cubeY:6 
这个坐标是第三宫(宫二)的第四个元素(1,6)
当 i = 2 , j = 4时   cubeX: 1-   cubeY:7
这个坐标是第三宫(宫二)的第五个元素(1,7)
当 i = 2, j = 5时    cubeX: 1-   cubeY:8
这个坐标是第三宫(宫二)的第六个元素(1,8)
当 i = 2 , j = 6时   cubeX: 2-   cubeY:6
这个坐标是第三宫(宫二)的第七个元素(2,6)
当 i = 2 , j = 7时   cubeX: 2-   cubeY:7
这个坐标是第三宫(宫二)的第八个元素(2,7)
当 i = 2, j = 8时    cubeX: 2-   cubeY:8
这个坐标是第三宫(宫二)的第九个元素(2,8)

也就睡说当外循环走到i = 2 时间,课可以对宫二的元素进行判断是否存在重复事务元素
关键是将坐标(i,j)变成宫i的所有的坐标


*所以验证宫的做法就是:*
for(int i = 0; i < 9; i++){
	int[] cube = new int[9];
	for(int j = 0; j < 9; j++) {
	int cubeX = 3 * (i/3) + j/3;
	int cubeY = 3 * (i%3) + i%3;
	if(board[cubeX][cubeY] != '.') {
		if(cube[board[cubeX][cubeY] - 1] == '1') {
				return false;
		} else {
				cube[board[cubeX][cubeY] - '1'] = 1;
			   }
		}
	}
}

###全部代码:


package solution_36;

import java.util.Arrays;

import org.junit.Test;

public class Solution {
	
	public static boolean isValidSudoku(char[][] board) {
		
		for(int i = 0; i < 9; i++) {
			int[] row = new int[9];
			int[] col = new int[9];
			int[] cube = new int[9];
			
			for(int j = 0; j < 9; j++) {
				System.out.println("board[i][j] : [ i=" + i + "j = " + j + "]   -- 值: " + board[i][j]);
				if(board[i][j]!='.') {
					if(row[board[i][j] - '1'] == 1) {
						/*System.out.println("====");
						System.out.println(row[board[i][j]]);
						System.out.println("====");*/
						return false;
					} else {
						row[board[i][j] - '1'] = 1;
						System.out.println("row[]   " + Arrays.toString(row)    +  "  ----   board[i][j] =  " + board[i][j]);
					}
				}
				
				if(board[j][i] != '.') {
					if(col[board[j][i] - '1'] == 1) {
						return false;
					} else {
						col[board[j][i] - '1'] = 1;
						System.out.println("col[]    " + Arrays.toString(col)   + "----  board[j][i] = " + board[j][i]  );
					}
				}
				// 每一宫内行列的变化
				int cubeX = 3 * (i/3) + j/3;
				int cubeY = 3 * (i%3) + j%3;
				if(board[cubeX][cubeY] != '.') {
					if(cube[board[cubeX][cubeY] - '1'] == 1) {
						return false;
					} else {
						System.out.println("cubeX= " + cubeX  +  "   cubeY=" + cubeY);
						cube[board[cubeX][cubeY] - '1'] = 1;
						System.out.println("cube[]      " + Arrays.toString(cube)   +  " ---   board[cubeX][cubeY]   = " + board[cubeX][cubeY]);
					}
				}
			}
			
			System.out.println("row[]  "  +  Arrays.toString(row));
			System.out.println("col[]  "  +  Arrays.toString(col));
			System.out.println("cube[]  "  +  Arrays.toString(cube));
		}
		return true;
	}
	
	public static void main(String[] args) {
		// char[][] board = [['8','3','.','.','7','.','.','.','.']];
		
		char[][] board = {
						{'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'}
		};
		System.out.println(isValidSudoku(board));
	}
	
	
	@Test
	public void test01() {
		for(int i = 0; i < 9; i++) {
			for(int j = 0; j < 9; j++) {
				int cubeX = 3 * (i/3) + j/3;
				int cubeY = 3 * (i%3) + j%3;
				System.out.println("cubeX: " + cubeX  + "-   cubeY:" + cubeY);
			}
			System.out.println("----------------");
		}
	}
	
	
	@Test
	public void test02() {
		int[] a = new int[9];
		System.out.println(a.length);
	}
	
	
	
}

你可能感兴趣的:(数据结构与算法)