014. 解数独

1.题目链接:

37. 解数独

2.解题思路:

2.1.题目要求:

暂时的理解就是,编写一个程序然后自动填完数独,填完返回(不用求解各种不同的数独组合)

填的时候,数字要满足的规则:

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

# 思路

2.2.思路:

大概思路就是双层 for 一层横一层竖,然后遍历 1 - 9 满足条件就下一层,直到填满,填满了直接返回,卡住或者没填满不符合条件就返回false。

(这里定义的是布尔类型,可以只填满一次就返回)

2.3.回溯三部曲:

2.3.1.确定回溯函数参数

因为解数独找到一个符合的条件(就在上面N叉树的叶子节点上)立刻就返回,相当于找从根节点到叶子节点一条唯一路径,所以需要使用bool返回值。

代码如下:

bool backtracking(vector<vector<char>>& board)

2.3.2.确定终止条件

没有,填满棋盘自然终止,但是会有遇见一个空1-9都填不进去的情况,需要向上递归,查找下一个解,也就是返回false,在单层遍历上有解释。

2.3.3.确定单层遍历逻辑

双for遍历整个棋盘,跳过非空格的格子,然后在能遍历的格子上,尝试 '1' - '9' (字符串) 合不合适,合适就放并继续向下递归去填 数字 ,这里会有个东西接着递归的判断,判断为 true ,就会一层层向上返回,这种返回有三种情况,第一种是棋盘被填满的返回,那这样,就不会触发下面回溯的逻辑,直接向上一层层结束第二种是没填满,这一格填1-9都不合适,那这样for(1-9)就遍历完结束了,然后进行回溯的操作,继续遍历来填1-9。第三种就是1-9都不合适在向下遍历的过程中,那这样,就会慢慢的一层层向上回溯,自然结束整个函数

bool backtracking(vector<vector<char>>& board) {

    for (int i = 0; i < board.size(); i++) {        // 遍历行
        for (int j = 0; j < board[0].size(); j++) { // 遍历列
            if (board[i][j] != '.') continue;
            for (char k = '1'; k <= '9'; k++) {     // (i, j) 这个位置放k是否合适
                if (isValid(i, j, k, board)) {
                    board[i][j] = k;                // 放置k
                    if (backtracking(board)) return true; // 如果找到合适一组立刻返回
                    board[i][j] = '.';              // 回溯,撤销k
                }
            }
            return false;                           // 9个数都试完了,都不行,那么就返回false
        }
    }
    return true; // 遍历完没有返回false,说明找到了合适棋盘位置了
}

2.3.4判断棋盘是否合法

判断棋盘是否合法有如下三个维度:

  • 同行是否重复
  • 同列是否重复
  • 9宫格里是否重复

代码如下:

bool isValid(int row, int col, char val, vector<vector<char>>& board) {
    for (int i = 0; i < 9; i++) { // 判断行里是否重复
        if (board[row][i] == val) {
            return false;
        }
    }
    for (int j = 0; j < 9; j++) { // 判断列里是否重复
        if (board[j][col] == val) {
            return false;
        }
    }
    int startRow = (row / 3) * 3;
    int startCol = (col / 3) * 3;
    for (int i = startRow; i < startRow + 3; i++) { // 判断9方格里是否重复
        for (int j = startCol; j < startCol + 3; j++) {
            if (board[i][j] == val ) {
                return false;
            }
        }
    }
    return true;
}

2.4.总代码:

class Solution {
private:
bool backtracking(vector<vector<char>>& board) {
    for (int i = 0; i < board.size(); i++) {        // 遍历行
        for (int j = 0; j < board[0].size(); j++) { // 遍历列
            if (board[i][j] == '.') {
                for (char k = '1'; k <= '9'; k++) {     // (i, j) 这个位置放k是否合适
                    if (isValid(i, j, k, board)) {
                        board[i][j] = k;                // 放置k
                        if (backtracking(board)) return true; // 如果找到合适一组立刻返回
                        board[i][j] = '.';              // 回溯,撤销k
                    }
                }
                return false;  // 9个数都试完了,都不行,那么就返回false 
            }                
        }
    }
    return true; // 遍历完没有返回false,说明找到了合适棋盘位置了
}
bool isValid(int row, int col, char val, vector<vector<char>>& board) {
    for (int i = 0; i < 9; i++) { // 判断行里是否重复
        if (board[row][i] == val) {
            return false;
        }
    }
    for (int j = 0; j < 9; j++) { // 判断列里是否重复
        if (board[j][col] == val) {
            return false;
        }
    }
    int startRow = (row / 3) * 3;
    int startCol = (col / 3) * 3;
    for (int i = startRow; i < startRow + 3; i++) { // 判断9方格里是否重复
        for (int j = startCol; j < startCol + 3; j++) {
            if (board[i][j] == val ) {
                return false;
            }
        }
    }
    return true;
}
public:
    void solveSudoku(vector<vector<char>>& board) {
        backtracking(board);
    }
};

3.遇见的问题:

1.填满的返回过程?

(主要是{}的分界没好好的区分开造成的混乱)

没事了,for里面的for的return...

2. 返回ture和false又没东西接着,干啥用的?

哦哦,遇见ture会终止当前循环。

3.

4.记录:

12.05

有点难才有意思嘛,不过做不出来也很合理对吧,

看代码,一层层层层层层层层层层层层的,头大...

12.12

欸,N皇后和解数独都没写代码,算了,赶快过一遍,假期进度刷起来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值