leetcode36 - Valid Sudoku - medium
Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules:
1. Each row must contain the digits 1-9 without repetition.
2. Each column must contain the digits 1-9 without repetition.
3. Each of the 9 3x3 sub-boxes of the grid must contain the digits 1-9 without repetition.
The Sudoku board could be partially filled, where empty cells are filled with the character '.'.
1.brute force O(n^3)。
对每个有数字的格子,去检查横竖方有没有冲突。
2.模拟法 O(n^2)。
重点在于i嵌套j分别从0~8的时候,i动得慢,j动得快,怎么数学处理i,j,制造真正应用的下标,从而让下标的运动轨迹变成你想要的横扫描,列扫描,块扫描。
横扫描:board[i][j],固定行的时候变列数。
列扫描:board[j][i], 固定列的时候变行数。
块扫描: board[i / 3 * 3 + j / 3 ][i % 3 *3 + j % 3 ],i变换出九个块的起始坐标(0,0)(0,3)(0,6)(3,0)...,j变换出九个块的扫描偏移坐标(0,0)(0,1)(0,2)(1,0)...
细节:
1.块扫描的坐标变化里,i/3*3是一种把粒度降低缓慢变化的感觉,i从0~8的变化中,这个会按000333666来变化,j/3是000111222,两者合并用于变化行坐标。
i%3*3是一种快速突变但循环的感觉,i从0~8的变化中,这个会按036036036来变化,j%3是012012012,两者合并用于变化列坐标。
2.三个set在i循环内部初始化。因为要检查新一行/列/方块了
3.这题写的二重循环中,i j的意义不再是纵坐标,横坐标了,而是第几轮扫描,该轮扫描内的偏移辅助指针。
4.检查set是否存在当前对象前,要先预判是不是为空格子,只对非空数字做有意义的判断。
实现:
class Solution { public boolean isValidSudoku(char[][] board) { // P1: 注意要先预判是不是为空格子,要是空格子以前出现过同样的空格子结果你判出现重复了,那不是很蠢。 for (int i = 0; i < 9; i++) { Set<Character> row = new HashSet<>(); Set<Character> col = new HashSet<>(); Set<Character> cube = new HashSet<>(); for (int j = 0; j < 9; j++) { // scan row if (board[i][j] != '.' && !row.add(board[i][j])) { return false; } // scan col if (board[j][i] != '.' && !col.add(board[j][i])) { return false; } // scan cube int x = i / 3 * 3 + j / 3, y = i % 3 * 3 + j % 3; if (board[x][y] != '.' && !cube.add(board[x][y])) { return false; } } } return true; } }