leetcode--37--Sudoku Solver

 转载请注明出处:http://write.blog.csdn.net/postedit/52739077

原题:Sudoku Solver

 

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

Empty cells are indicated by the character '.'.

You may assume that there will be only one unique solution.


备注:满足条件的填充要满足,每行、每列、每个方格(9个小方格)数字包含1-9

即数字不重复。



解答:

C++版本

class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) {
        solve(board);
    }
private:
    bool solve(vector<vector<char>>& board) {
        for (int r = 0; r < 9; r++) {
            for (int c = 0; c < 9; c++) {
                if (board[r][c] == '.') {
                    for (char d = '1'; d <= '9'; d++) {
                        if (isValid(board, r, c, d)) {
                            board[r][c] = d;
                            if (solve(board)) return true;
                        }
                    }
                    board[r][c] = '.';
                    return false;
                }
            }
        }
        return true;
    }
	
bool isValid(vector<vector<char>>& board, int r, int c, char d) {
        for (int row = 0; row < 9; row++)
            if (board[row][c] == d) return false;
        for (int col = 0; col < 9; col++)
            if (board[r][col] == d) return false;
        for (int row = (r / 3) * 3; row < (r / 3 + 1) * 3; row++) //判断小方格是否重复
            for (int col = (c / 3) * 3; col < (c / 3 + 1) * 3; col++)
                if (board[row][col] == d) return false;
        return true;
    }
};





思路:

和迷宫问题类似,这道题也是采用回溯的方法,这也是最容易想到的解决方法。

数据检验函数isValid用来检验数据是否重复,比较好理解,关键是回溯方式的理解。

 

当然,这里的回溯法必然要用到递归来实现,对于一个未完成的数独,我们只有对发现的第一个空格(程序中用.”表示)用全部有效数字(通过isValid检验的数)验证一遍,才知道是否能成功,这里的双层for循环就是为了发现第一个空格。

 

第一个空格每次填充一个有效数字后,就可以调用solve函数来验证填充完这个数后,是否能成功,这也是递归的灵魂,是一种归纳的思想,犹如,我们需要求解f(n)的值,可以使用f(n-1),而且认为f(n-1)是已知的。

 

递归返回的条件,如果找到任意一个有效解就返回true;或者整个空格所有有效数都用完了,依然没有找不到成功解,返回false;或者没有找到空格,说明大功告成,这就是我们想要的数独,当然要返回true

 

需要注意的是,board[r][c] = '.'语句的作用。由于使用的board是引用方式,那么任意一处的修改都会影响其他地方的使用。所以所有值都不满足时,所在方格要还原为“.”,这样就不会影响上层递归的判断。

 

在实际运行过程中是这样的:

 

1个空格填充一个有效数字,比如是1,进入solve...   //第 1 层递归

    2个空格(相对最原始的表)填充一个有效数字,比如是4,进入solve...   //第 2 次递归

        3空格填充一个有效数字,比如是3,进入solve...  //第 3 层递归

        ...  

             倒数第2个空格填充一个有效数字,比如是7,进入solve... //倒数第 2 层递归

                     最后一个空格填充一个有效数字,发现找不到这样的有效数字 //最后一层

                     最后一个空格还原为.’返回false,退回到倒数上层递归...

 

           上层递归是填充倒数第2个空格那层,说明填7不对,改为另一个有效数字 //倒数第 2 层递归

           比如4,继续solve...

 

                   最后一个空格填充一个有效数字,发现找也不到这样的有效数字 //又回到最后一层

                   最后一个空格还原为.’返回false,退回到倒数上层递归...

 

          上层递归是填充倒数第2个空格那层,说明填4也不对,改为另一个有效数字 //倒数第 2 层递归

          比如2,继续solve...


                 最后一个空格填充一个有效数字,发现找不到这样的有效数字 //第三次回到最后一层

              

      继续回到上层循环,但是发现有效数字用完了,那就再回到上层 //回到倒数第二层递归,但是数字已用尽

 

    上层递归是填充倒数第3个空格那层,说明第三层也要改数字了 //倒数第三层递归


   .......

   .......

   所有结果都无效,最终函数要回到第一层递归,假设第一层(就是第一个空格处)可用的数字有3个,1、5、8

   那说明1已经试验过,统统无效,那么就会去尝试5,重复上面的整个过程,可能有效,也可能无效,如果无效

   那说明8一定有效,因为题目保证有唯一一个正确答案。

      

 

。。。。。。。

上面就是回溯和递归的全过程,需要说明的一点事,可能在没有填充完最后的空格就发现找不到有效数字了,这样递归就提前返回到上层,最理想的状态是所有递归都能找到合理数字,都不要还原数字(把答案中所有的1抠掉就是一个例子)。说了那么多,就是为了说明这种深度优先遍历的执行步骤,计算机其实很傻,但是很听话,不会出错,层层递归,不满足就返回上层,修改值,重新进入,直到找到答案为止。

 

 

       

 

 

         

      

 

 

 

 

 

 

 

LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值