37. Sudoku Solver (Hard) Unoptimized

Description:

Write a program to solve a Sudoku puzzle by filling the empty cells.

A sudoku solution must satisfy all of the following rules:

  1. Each of the digits 1-9 must occur exactly once in each row.
  2. Each of the digits 1-9 must occur exactly once in each column.
  3. Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.

Empty cells are indicated by the character '.'.

A sudoku puzzle...
...and its solution numbers marked in red.

Note:

  • The given board contain only digits 1-9 and the character '.'.
  • You may assume that the given Sudoku puzzle will have a single unique solution.
  • The given board size is always 9x9.

Solutions:

Solution1: my vanilla version

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        row_unseen = []
        column_unseen = []
        square_unseen = []
        row_seen = []
        column_seen = []
        square_seen = []
        for i in range(9):
            row_unseen.append(set(range(1,10)))
            column_unseen.append(set(range(1,10)))
            square_unseen.append(set(range(1,10)))
            row_seen.append(set())
            column_seen.append(set())
            square_seen.append(set())

        for i in range(9):
            for j in range(9):
                num = board[i][j]
                if num != ".":
                    num = int(num)
                    row_unseen[i].remove(num)
                    column_unseen[j].remove(num)
                    square_unseen[3*(i//3) + j//3].remove(num)
                    row_seen[i].add(num)
                    column_seen[j].add(num)
                    square_seen[3*(i//3) + j//3].add(num)
                    
        candidate = {}
        for i in range(9):
            for j in range(9):
                num = board[i][j]
                if num == ".":
                    candidate[(i,j)] = list(row_unseen[i] & column_unseen[j] & square_unseen[3*(i//3)+j//3])
                    
        self.dfs(row_seen,column_seen,square_seen,candidate,0,board)
                    
    def dfs(self,row_seen,column_seen,square_seen,candidate,index,board):
        if index == 81:
            return True,board
        
        i,j = index//9,index%9
        if (i,j) in candidate:
            for choice in candidate[(i,j)]:
                if choice in row_seen[i] | column_seen[j] | square_seen[3*(i//3) + j//3]:
                    continue
                row_seen[i].add(choice)
                column_seen[j].add(choice)
                square_seen[3*(i//3) + j//3].add(choice)
                board[i][j] = str(choice)
                flag,board = self.dfs(row_seen,column_seen,square_seen,candidate,index+1,board)
                if flag == True:
                    return True,board
                else:
                    row_seen[i].remove(choice)
                    column_seen[j].remove(choice)
                    square_seen[3*(i//3) + j//3].remove(choice)
                    board[i][j] = "."
            return False,board
        else:
            return self.dfs(row_seen,column_seen,square_seen,candidate,index+1,board)

Performance:

  • Runtime: 192 ms, faster than 62.95% of Python3 online submissions for Sudoku Solver.
  • Memory Usage: 13.3 MB, less than 28.67% of Python3 online submissions for Sudoku Solver.
  • Solving time: ~2h (一遍AC)

Solution2: a shorter one

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        
        row_seen = []
        column_seen = []
        square_seen = []
        for i in range(9):
            row_seen.append(set())
            column_seen.append(set())
            square_seen.append(set())

        unsolve = set()
        for i in range(9):
            for j in range(9):
                num = board[i][j]
                if num != ".":
                    num = int(num)
                    row_seen[i].add(num)
                    column_seen[j].add(num)
                    square_seen[3*(i//3) + j//3].add(num)
                else:
                    unsolve.add((i,j))
                    
        self.dfs(row_seen,column_seen,square_seen,unsolve,0,board)
                    
    def dfs(self,row_seen,column_seen,square_seen,unsolve,index,board):
        if index == 81:
            return True
        
        i,j = index//9,index%9
        if (i,j) in unsolve:
            for choice in range(1,10):
                if choice in row_seen[i] | column_seen[j] | square_seen[3*(i//3) + j//3]:
                    continue
                row_seen[i].add(choice)
                column_seen[j].add(choice)
                square_seen[3*(i//3) + j//3].add(choice)
                board[i][j] = str(choice)
                flag = self.dfs(row_seen,column_seen,square_seen,unsolve,index+1,board)
                if flag == True:
                    return True
                else:
                    row_seen[i].remove(choice)
                    column_seen[j].remove(choice)
                    square_seen[3*(i//3) + j//3].remove(choice)
                    board[i][j] = "."
            return False
        else:
            if board[i][j] in row_seen[i] | column_seen[j] | square_seen[3*(i//3) + j//3]:
                return False
            return self.dfs(row_seen,column_seen,square_seen,unsolve,index+1,board)

Performance: worse

  • Runtime: 328 ms, faster than 47.27% of Python3 online submissions for Sudoku Solver.
  • Memory Usage: 13.2 MB, less than 69.45% of Python3 online submissions for Sudoku Solver.

你可能感兴趣的:(37. Sudoku Solver (Hard) Unoptimized)