【算法面试通关40讲】33 - 面试题:数独问题

Leetcode-36. 有效的数独

判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

在这里插入图片描述
上图是一个部分填充的有效的数独。

数独部分空格内已填入了数字,空白格用 ‘.’ 表示。

示例 1:

输入:
[
  ["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"]
]
输出: true

示例 2:

输入:
[
  ["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"]
]
输出: false
解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。
     但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。

说明:

  • 一个有效的数独(部分已被填充)不一定是可解的。
  • 只需要根据以上规则,验证已经填入的数字是否有效即可。
  • 给定数独序列只包含数字 1-9 和字符 ‘.’ 。
  • 给定数独永远是 9x9 形式的。

解法:遍历整个正方形,只要一直行中没有重复的,列中没有重复的,小正方形中没有重复的即可,时间复杂度,空间复杂度都是O(1)

  • Java
    使用HashSet,缺点慢,读取hashset时间慢于数组
class Solution {
    public boolean isValidSudoku(char[][] board) {
        for(int i = 0; i<9; i++){
            HashSet<Character> rows = new HashSet<Character>();
            HashSet<Character> columns = new HashSet<Character>();
            HashSet<Character> cube = new HashSet<Character>();
            for (int j = 0; j < 9;j++){
                if(board[i][j]!='.' && !rows.add(board[i][j]))
                    return false;
                if(board[j][i]!='.' && !columns.add(board[j][i]))
                    return false;
                int RowIndex = 3*(i/3);
                int ColIndex = 3*(i%3);
                if(board[RowIndex + j/3][ColIndex + j%3]!='.' && !cube.add(board[RowIndex + j/3][ColIndex + j%3]))
                    return false;
            }
        }
        return true;
    }
}

使用数组,速度会快上很多

class Solution {
    public boolean isValidSudoku(char[][] board) {
        for (int i=0;i<9;i++) {
            int[] cols = new int[9];
            int[] rows = new int[9];
            int[] blocks = new int[9];
            for (int j=0;j<9;j++) {
                // 遍历行,-‘1’是为了用0-8索引存下1-9
                if (board[i][j] == '.') {}
                else if (rows[board[i][j]-'1']==1) return false;
                else rows[board[i][j]-'1']=1;
                // 遍历列
                if (board[j][i] == '.') {}
                else if (cols[board[j][i]-'1']==1) return false;
                else cols[board[j][i]-'1']=1;
                // 遍历块,将ij坐标系转换到正方形坐标系,理解不了可以背
                int m = i/3*3 + j/3;
                int n = i%3*3 + j%3;
                if (board[m][n]== '.') {}
                else if (blocks[board[m][n]-'1']==1) return false;
                else blocks[board[m][n]-'1']=1;
            }
        }
        return true;
    }
}
  • Python
class Solution:
    def isValidSudoku(self, board: List[List[str]]) -> bool:
        for i in range(9):
            rows = [0]*9
            cols = [0]*9
            blocks = [0]*9
            for j in range(9):
                if board[i][j]=='.':pass
                elif rows[int(board[i][j])-1]==1: return False
                else: rows[int(board[i][j])-1]=1
                if board[j][i]=='.':pass
                elif cols[int(board[j][i])-1]==1: return False
                else: cols[int(board[j][i])-1]=1
                m, n = i//3*3 + j//3, i%3*3 + j%3
                if board[m][n]=='.':pass
                elif blocks[int(board[m][n])-1]==1: return False
                else : blocks[int(board[m][n])-1]=1
        return True
                

Leetcode-37. 解数独

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

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

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
    空白格用 ‘.’ 表示。
    在这里插入图片描述
    一个数独。
    在这里插入图片描述
    答案被标成红色。

Note:

给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。

解法:使用dfs,每个格子查看能填的数,如果能填,填进去在将填完的board重新调用,如果有格子1-9都不能填了,return false,如果遍历到最后,所有格子都填完了,return true。时间复杂度,空间复杂度都是O(1)

在这里插入图片描述

  • Java
class Solution {
    public void solveSudoku(char[][] board) {
        if (board==null || board.length==0) return ;
        this.dfs(board);
    }
    public boolean dfs(char[][] board) {
        for (int i=0;i<board.length;i++){
            for (int j=0;j<board[0].length;j++) {
                if (board[i][j]=='.') {
                    for (char c='1';c<='9';c++) { // must be <=9, cant be <10,cause 10 is no more character
                        if (this.isValid(board, i, j, c)) {
                            board[i][j] = c;
                            boolean res= this.dfs(board);
                            if (res==true) return true;
                            else board[i][j]='.';
                        }
                    }
                    return false;
                }
            }
        }
        return true;
    }
    public boolean isValid(char[][] board, int row, int col, char c) {
        for (int i=0;i<9;i++) {
            if (board[row][i]!='.' && board[row][i]==c) return false;
            if (board[i][col]!='.' && board[i][col]==c) return false;
            int m = row/3*3 + i/3;
            int n = col/3*3 + i%3;
            if (board[m][n]!='.' && board[m][n]==c) return false;
        }
        return true;
    }
}
  • Python
class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        if not board: return 
        self.board = board
        self.dfs()
    def dfs(self):
        for i in range(len(self.board)):
            for j in range(len(self.board[0])):
                if self.board[i][j]=='.':
                    for c in range(1,10):
                        c = str(c)
                        if self.isValid(i,j,c): 
                            self.board[i][j] = c
                            res = self.dfs()
                            if res: return True
                            else: self.board[i][j] = '.'
                    return False
        return True
    def isValid(self,row,col,c):
        for i in range(9):
            if (self.board[row][i]==c): return False
            if (self.board[i][col]==c): return False
            m = row//3*3 + i//3
            n = col//3*3 + i%3
            if (self.board[m][n]==c): return False
        return True
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值