Leetcode算法——36、判断有效数独

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HappyRocking/article/details/83895928

判断一个 9*9 的数独面板是否是有效的。

如果已经被填充的数字满足以下条件,则说明是有效的:

  • 每一行只能包含无重复数字1-9
  • 每一列只能包含无重复数字1-9
  • 每一个 3*3 的子面板只能包含无重复数字1-9

备注:

  • 一个有效的数独面板(部分填充)不必是可解的
  • 只要被填充的数字满足有效条件即可
  • 数独面板可以只被部分填充,其他空缺的为字符’.’
  • 面板只能包含数字1-9或者字符’.’
  • 面板大小总是 9*9

Example 1:
Input:
[
[“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”]
]
Output: true

Example 2:
Input:
[
[“8”,“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”]
]
Output: false
Explanation: Same as Example 1, except with the 5 in the top left corner being
modified to 8. Since there are two 8’s in the top left 3x3 sub-box, it is invalid.

思路

1、定义法

按照数独的有效性定义,需要从行、列、3*3子块三个方面都满足数字的唯一性。

因此,可以分三个步骤,分别检验三个条件,只要有一个条件不满足,则说明数独无效。

1、检验每一行是否有重复数字。可以定义一个set,存放扫描过的数字,一旦新数字已经被包含在set中,则说明重复。
2、检验每一列是否有重复数字。与行同理。
3、检验每一个子块是否有重复数字。需要检查9个子块。

2、一次检验法

上述方法是分别检验三个条件,每个条件都需要遍历一遍所有的数字。

实际上,可以只通过一次遍历,来同时判断是否满足三个条件。

维护一个 set,这个set中存放三种格式的元素:

  • (int i, char c):二元组,表示第 i 行中存在 c 字符。
  • (char c, int i):二元组,表示第 i 列中存在 c 字符。
  • (i, j, c):三元组,表示第 [i, j] 个子块中存在 c 字符,其中 0 i , j 2 0\le i, j\le2

由于元组长度以及元素类型的不同,三种元素不会相互混合。

因此,每次扫描到一个数字,便生成 3 个对应的元组,分别判断是否存在于 set 中,如果存在,则说明数独无效;否则,将 3 个元组都加入到 set 中,继续扫描下一个数字。

python实现

def isValidSudoku(board):
    """
    :type board: List[List[str]]
    :rtype: bool
    依次判断3个有效条件是否全部满足。
    """
    
    def is_row_valid(board):
        '''
        判断一个数独的每一行是否都包含无重复数字1-9
        '''
        for row in board:
            char_set = set()
            for char in row:
                if char != '.':
                    if char in char_set:
                        return False
                    char_set.add(char)
        return True
    
    # 1、每一行一定要包含无重复数字1-9
    if not is_row_valid(board):
        return False
                
    # 2、每一列一定要包含无重复数字1-9
    board_reverse = [[board[i][j] for i in range(9)] for j in range(9)]
    if not is_row_valid(board_reverse):
        return False    
    
    # 3、每一个 3*3 的子面板一定要包含无重复数字1-9
    for i in range(3):
        for j in range(3):
            char_set = set()
            for ii in range(i*3, (i+1)*3):
                for jj in range(j*3, (j+1)*3):
                    char = board[ii][jj]
                    if char != '.':
                        if char in char_set:
                            return False
                        char_set.add(char)
    return True

def isValidSudoku2(board):
    """
    :type board: List[List[str]]
    :rtype: bool
    一次遍历,同时判断是否满足3个有效条件。
    """
    
    char_set = set()
    for i in range(9):
        for j in range(9):
            char = board[i][j]
            if char != '.':
                if (i, char) in char_set \
                    or (char, j) in char_set \
                    or (i//3, j//3, char) in char_set:
                        return False
                else:
                    char_set.add((i, char)) # 第i行的char字符
                    char_set.add((char, j))  # 第j列的char字符
                     # [i//3, j//3]位置的小面板的char字符
                    char_set.add((i//3, j//3, char))
    return True

if '__main__' == __name__:
    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"]
]
    print(isValidSudoku2(board))
    

猜你喜欢

转载自blog.csdn.net/HappyRocking/article/details/83895928