解数独(回溯算法)

说明

  1. 主函数 solveSudoku:

    • 调用 backtrack 函数尝试解决数独问题。
  2. 回溯函数 backtrack:

    • 遍历数独中的每个单元格。
    • 如果单元格为空('.'),尝试填充数字 1-9。
    • 检查是否可以放置数字,如果可以,放置后继续递归解决。
    • 如果递归返回 false,撤销当前数字,回溯尝试下一个数字。
  3. 验证函数 boxIndex:

    • 检查当前数字是否在同一行、同一列或同一 3x3 宫格中已经存在。

复杂度分析

  1. 时间复杂度

    • 在最坏情况下(填充的空格很多),复杂度接近 O(9m)O(9^{m})O(9m),其中 mmm 是空格的数量。
    • 辅助数组显著降低了检查的开销,实际效率更高。
  2. 空间复杂度

    • 辅助数组的空间复杂度为 O(9×9)O(9 \times 9)O(9×9),递归栈的深度最大为 O(81)。
function solveSudoku(&$board) {
    // 定义辅助数组,记录每行、每列、每个 3x3 宫格是否已经存在某个数字
    $rows = array_fill(0, 9, array_fill(0, 9, false));
    $cols = array_fill(0, 9, array_fill(0, 9, false));
    $boxes = array_fill(0, 9, array_fill(0, 9, false));

    // 初始化辅助数组
    for ($i = 0; $i < 9; $i++) {
        for ($j = 0; $j < 9; $j++) {
            if ($board[$i][$j] !== '.') {
                $num = intval($board[$i][$j]) - 1; // 转换为索引
                $rows[$i][$num] = true;
                $cols[$j][$num] = true;
                $boxes[$this->boxIndex($i, $j)][$num] = true;
            }
        }
    }

    // 开始填充数独
    $this->backtrack($board, 0, $rows, $cols, $boxes);
}

// 辅助函数:回溯填充
function backtrack(&$board, $pos, &$rows, &$cols, &$boxes) {
    // 找到下一个需要填充的空格
    for ($i = $pos; $i < 81; $i++) {
        $row = intdiv($i, 9);
        $col = $i % 9;

        if ($board[$row][$col] === '.') {
            // 尝试填充 1-9
            for ($num = 0; $num < 9; $num++) {
                $boxIdx = $this->boxIndex($row, $col);
                if (!$rows[$row][$num] && !$cols[$col][$num] && !$boxes[$boxIdx][$num]) {
                    // 更新状态
                    $board[$row][$col] = strval($num + 1);
                    $rows[$row][$num] = $cols[$col][$num] = $boxes[$boxIdx][$num] = true;

                    // 递归填充下一格
                    if ($this->backtrack($board, $i + 1, $rows, $cols, $boxes)) {
                        return true;
                    }

                    // 回溯
                    $board[$row][$col] = '.';
                    $rows[$row][$num] = $cols[$col][$num] = $boxes[$boxIdx][$num] = false;
                }
            }
            return false; // 如果当前格无法填充,返回 false
        }
    }
    return true; // 填充完成
}

// 辅助函数:计算当前格的 3x3 宫格索引
function boxIndex($row, $col) {
    return intdiv($row, 3) * 3 + intdiv($col, 3);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值