【算法数据结构】leetcode37 解数独


37. 解数独 - 力扣(LeetCode)

题目描述:

题目要求每一行 ,每一列,每个3*3 的子框只能出现一次。每个格子的数字范围1-9.

需要遍历每个空格填入可能的数字,并验证符合规则。如果符合就填入,不符合就回溯。

解法:

回溯算法通常用于解决这种需要试错的问题。当发现当前路径无解时候,返回上一步重新选择。

需要遍历每个空格,找到需要填写的空格,对每个空格尝试填入1-9,检查这个数字是否满足行,列 ,子框的要求。如果满足就填入这个数字,递归进行下一个空格,如果后续处理中,发现无法填入下去,就需要回溯。恢复这个空格的状态,尝试下一个可能的数字。

检查某个数字是否可以填入当前位置

对于 位置(i,i)需要检查i 行,j 列,所在的子框是否有这个数字,属于第几个子框可以用 (i/3 )*3,(j/3 )*3来确定 。i=4 4/3=1 1*3=3 ,起始行是3 ,遍历这个3*3的子框。

对于每个空格最多检查1-9个数字。,每个数字需要检查三个方向,最坏情况可能出现重复检查。

优化方法

用哈希表或者数据记录行,列,子框。已经出现的数字。用3个二维数组,记录rowi 表示第i行是否存在数组num,colj 表示第j 列是否存在数据num,boxk 表示第k 个子框中是否存咋这个数字num,

k 可以通过 i//3*3 +j//3 来计算

i=0 ,j=0 ,k=0

i=3,j=3 ,k=4 在第四个子框。

预处理这三个数组,遍历整个数独,对这个对每个非空的格子,将对应的行列,子框中盖数字标记为存在。比如broad_i 为5 ,那么需要row_i 设置为true ,col_j 设置为true ,box_k (k为子框的索引)设置为true。

对每个空格尝试填入1-9 数字中的一个,

初始化 9X10 数组 其中索引 0不用

步骤

  1. 预处理三个数组row、col、box,记录每个行、列、子框中已经存在的数字。

  2. 收集所有需要填写的空格的位置,存入一个列表spaces。

  3. 编写一个回溯函数,参数是当前处理到spaces中的第pos个位置。当pos等于spaces的长度时,说明已经填完所有空格,返回True。

  4. 对于当前处理的空格位置(i,j),尝试填入1到9中的一个数字d。如果该数字满足rowid、coljd、boxkd都为False,那么将该数字填入,并更新这三个数组的状态。然后递归处理pos+1的位置。如果递归返回True,说明后续的填写都成功,那么当前的选择是正确的,直接返回True。如果递归返回False,则说明后续无法完成,需要回溯,恢复三个数组的状态,并将boardij恢复为'.',然后尝试下一个数字。

  5. 如果所有数字都尝试过且都不行,则返回False,触发上一层递归的回溯。

这样,当递归函数返回True时,说明已经找到解,此时board已经被正确填充。

复制代码
    # 初始化 3个数组
    row = [[False] * 10 for i in range(9)]
    print(row)  # 每行十个元素
    col = [[False] * 10 for i in range(9)]

    box = [[False] * 10 for i in range(9)]

[[False, False, False, False, False, False, False, False, False, False],
 [False, False, False, False, False, False, False, False, False, False],
 [False, False, False, False, False, False, False, False, False, False],
 [False, False, False, False, False, False, False, False, False, False], 
[False, False, False, False, False, False, False, False, False, False],
 [False, False, False, False, False, False, False, False, False, False], 
[False, False, False, False, False, False, False, False, False, False], 
[False, False, False, False, False, False, False, False, False, False],
 [False, False, False, False, False, False, False, False, False, False]]

遍历数组填充已经有的数字 spaces 用于记录空格的位置

复制代码
# 遍历整个数组 记录每个行 ,列子框中已经存在的数字
    spaces = []
    for i in range(9):
        for j in range(9):
            if board[i][j] != '.':
                d = int(board[i][j])
                row[i][d] = True
                col[j][d] = True
                k = (i // 3) * 3 + (j // 3)
                box[k][d] = True  # 第k 个箱子的d 是否存在
            # 保存空格的位置到spaces
            else:
                spaces.append((i, j))
    print("空格的位置", spaces)

空格的位置 (0, 2), (0, 3), (0, 5), (0, 6), (0, 7), (0, 8), (1, 1), (1, 2), (1, 6), (1, 7), (1, 8), (2, 0), (2, 3), (2, 4), (2, 5), (2, 6), (2, 8), (3, 1), (3, 2), (3, 3), (3, 5), (3, 6), (3, 7), (4, 1), (4, 2), (4, 4), (4, 6), (4, 7), (5, 1), (5, 2), (5, 3), (5, 5), (5, 6), (5, 7), (6, 0), (6, 2), (6, 3), (6, 4), (6, 5), (6, 8), (7, 0), (7, 1), (7, 2), (7, 6), (7, 7), (8, 0), (8, 1), (8, 2), (8, 3), (8, 5), (8, 6)

d = int(boardij) 填充的数字作为下标

row: rowid=True

复制代码
[[False, False, False, True(3), False, True(5), False, True(7), False, False],
 [False, True(1), False, False, False, True(5), True(6), False, False, True(9)],
 [False, False, False, False, False, False, True(6), False, True(8), True(9)], 
[False, False, False, True(3), False, False, True(6), False, True(8), False],
 [False, True(1), False, True(3), True(4), False, False, False, True(8), False],
 [False, False, True(2), False, False, False, True(6), True(7), False, False], 
[False, False, True(2), False, False, False, True(6), False, True(8), False],
 [False, True(1), False, False, True(4), True(5)), False, False, False, True(9)],
 [False, False, False, False, False, False, False, True(7), True(8), True(9)]]

col : coljd=true 纵坐标作为 行 d作为列

第一列 4 5 6 7 8

False, False, False, False, True(4), True(5), True(6), True(7), True(8), False

复制代码
[[False, False, False, False, True(4), True(5), True(6), True(7), True(8), False], 
[False, False, False, True, False, False, True, False, False, True], 
[False, False, False, False, False, False, False, False, True, False],
 [False, True, False, False, True, False, False, False, True, False],
 [False, True, True, False, False, False, True, True, True, True], 
[False, False, False, True, False, True, False, False, False, True],
 [False, False, True, False, False, False, False, False, False, False], 
[False, False, False, False, False, False, True, True, True, False], 
[False, True, False, True, False, True, True, False, False, True]]

box : k = (i // 3) * 3 + (j // 3)

boxkd = True # 第k 个箱子的d 是否存在

例如 board43=8 k=(4//3)*3 +(3//1) =4 第4个子框 第8个标记为true

复制代码
[[False, False, False, True, False, True, True, False, True, True], 
[False, True, False, False, False, True, False, True, False, True],
 [False, False, False, False, False, False, True, False, False, False], 
[False, False, False, False, True, False, False, True, True, False],
 [False, False, True, True, False, False, True, False, True(8), False], 
[False, True, False, True, False, False, True, False, False, False],
 [False, False, False, False, False, False, True, False, False, False],
 [False, True, False, False, True, False, False, False, True, True], 
[False, False, True, False, False, True, False, True, True, True]]

定义回溯

复制代码
# 定义回溯
    def backtrack(pos):
        print("pos", pos)
        if pos == len(spaces):  # 当pos 等于spaces长度时候说明已经填写完 ,返回true
            print("结果", board)
            return True
        i, j = spaces[pos]
        k = (i // 3) * 3 + (j // 3)
        for d in range(1, 10):  # 对这个位置尝试填充1-9
            if not row[i][d] and not col[j][d] and not box[k][d]:  # 满足为false 时候填入
                row[i][d] = True
                col[j][d] = True
                box[k][d] = True
                board[i][j] = str(d)
                if backtrack(pos + 1):
                    return True
                # 回溯
                row[i][d] = False
                col[j][d] = False
                box[k][d] = False
                board[i][j] = '.'  # 恢复空格
        return False

    backtrack(0)

代码

复制代码
class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        # 初始化三个数组
        row=[[False] *10 for _ in range(9)]
        col=[[False] *10 for _ in range(9)]
        box=[[False] *10 for _ in range(9)]
        spaces=[] # 记录空格位置
        # 遍历数组填充已经有的数字
        for i in range(9):
            for j in range(9):
                if board[i][j]!='.':
                    d=int(board[i][j])
                    row[i][d]=True
                    col[j][d]=True
                    k=(i//3)*3+(j//3)
                    box[k][d]=True
                else:
                    spaces.append((i,j)) # 记录空格的坐标
        def  backtrack(pos):
            if pos ==len(spaces):#遍历完了所有空格
                return True
            i,j=spaces[pos] # 取出当前位置的空格坐标
            k=(i//3)*3+(j//3)
            for d in range(1,10):  # 尝试对该位置填充1-9
                
                if row[i][d]==False and col[j][d]==False and box[k][d]==False:
                    row[i][d]=True
                    col[j][d]=True
                    box[k][d]=True
                    board[i][j]=str(d)
                    if backtrack(pos+1):
                        return True
                    #不满足  回溯
                    row[i][d]=False
                    col[j][d]=False
                    box[k][d]=False
                    board[i][j]='.' 
            return False
        backtrack(0)
相关推荐
智者知已应修善业几秒前
【51单片机8个LED的花样12亮34熄56间隔78闪烁3秒3闪烁】2023-11-4
c++·经验分享·笔记·算法·51单片机
老鱼说AI7 分钟前
统计学习方法第五章:从浅入深解析决策树
人工智能·深度学习·算法·决策树·机器学习·学习方法
KaMeidebaby9 分钟前
卡梅德生物技术快报|蛋白修饰调控 NETosis 分子机制及实验研究进展
前端·数据库·人工智能·算法·百度
初中就开始混世的大魔王13 分钟前
5 Fast DDS-Discovery
网络·c++·算法·中间件
Deep-w13 分钟前
【MATLAB】基于模型预测控制的自适应巡航车辆过渡工况安全控制研究
开发语言·人工智能·算法·机器学习·matlab
运行时记录14 分钟前
Sirchmunk 让搜索随查询自进化
算法
欧米欧16 分钟前
C++进阶数据结构之红黑树
数据结构
浮生望18 分钟前
双指针算法面试通关指南:从入门到精通
算法
SimpleLearingAI21 分钟前
PyTorch & Numpy 实现线性回归详解
人工智能·算法·多模态大模型
papership21 分钟前
【入门级-数据结构-1、线性结构:链 表(单链表、双向链表、循环链表 )】
数据结构·算法·链表