leetcode刷题-37解数独

题目

编写一个程序,通过已填充的空格来解决数独问题。

一个数独的解法需遵循如下规则:

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 '.' 表示。

思路

使用暴力破解是不现实的,其需要 9^81次运算。

因此与数独相同,都需要用到回溯的思想。

其算法可以简化为:

1.从头开始选择到一个空白格

2.选择数字 1-9中的一个,判断是否符合标准(不能重复出现在行,列,3*3方格中)

  2.1 填入数字

  2.2 检查其是否已经找出了数独的解

    2.2.1 若抵达最后一格,获得数独的解

    2.2.2 若没有抵达最后一格,放置下一个数字

    2.2.3 若不存在解,删除当前数字

实现

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        flag = False
        line = [[]for i in range(9)]
        arr = [[]for i in range(9)]
        chunk = [[]for i in range(9)]

        def valid_num(num, row, col):
            num_flag = num not in line[row] and num not in arr[col] and num not in chunk[row//3*3+col//3]
            return num_flag
        
        def remove(num, row, col):
            i = line[row].index(num)
            j = arr[col].index(num)
            k = chunk[row//3*3+col//3].index(num)
            del line[row][i]
            del arr[col][j]
            del chunk[row//3*3+col//3][k]
            board[row][col] = '.'

        def add(num, row, col):
            line[row].append(num)
            arr[col].append(num)
            chunk[row//3*3+col//3].append(num)
            board[row][col] = num

        def check(row, col):
            if row == 8 and col == 8:
                nonlocal flag
                flag = True
            else:
                if col == 8:
                    backtrace(row + 1, 0)
                else:
                    backtrace(row, col + 1)

        def backtrace(row, col):
            if board[row][col] == '.':
                for m in range(1,10):
                    d= str(m)
                    if valid_num(d, row, col) is True:
                        add(d, row, col)
                        check(row, col)
                        if not flag:
                            remove(d, row, col)
            else:
                check(row, col)
        
        vex = len(board)
        for i in range(vex):
            for j in range(vex):
                get = board[i][j]
                k = i//3*3+j//3
                if get is not '.':
                    line[i].append(get)
                    arr[j].append(get)
                    chunk[k].append(get)
        # flag = False
        backtrace(0, 0)

值得注意的是,在check函数中,需要申明nonlocal flag在函数或其他作用域中使用外层(非全局)变量,因为其对flag值进行了修改,否则无法使用。此处不能使用global。

 
posted @ 2020-08-03 15:30  maoguai  阅读(170)  评论(0编辑  收藏  举报