数据结构---数独问题

文章详细介绍了使用回溯法解决数独问题的JAVA实现,重点在于isValid函数的逻辑和递归的处理。在原来的代码中,由于returnfalse出现在returntrue之前,导致解决方案不正确。修正这个问题后,代码能够正确地解决数独问题并返回解决方案。
摘要由CSDN通过智能技术生成


其思想就是 回溯法,相比n皇后问题只考虑行,数独问题同时考虑行和列进行定位。
n皇后问题博文: n皇后问题
在这里插入图片描述

力扣37题,困难

解题思路

遍历行列,逐个位置定位,然后判断当前位置能放什么位置
关于子方格内9个数组不重复的判断,是行列偏移量+行/列增量

行列偏移量:3*(row/3)
行增量:i/3
列增量:i%3
在这里插入图片描述

通过递归实现回溯
在这里插入图片描述

JAVA实现

private static void printArr(char[][] arr) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
    }

    /**
     * 判断当前位置(row,col)能否放置数字num
     * @param board
     * @param row
     * @param col
     * @param num
     * @return
     */
    public static boolean isValid(char[][] board,int row,int col,char num){
        for (int i =0;i<9;i++){
            //判断行
            if(board[i][col]==num){
                return false;
            }
            //判断列
            if (board[row][i]==num){
                return false;
            }
            //判断小方格里面
            //3*(row/3)是行列的偏移量
            //i/3是行的增量:0,0,0,1,1,1,2,2,2
            //i%3是列的增量:0,1,2,0,1,2,0,1,2
            if(board[3*(row/3)+i/3][3*(col/3)+i%3]==num){
                return false;
            }
        }
        //合法的插入位置
        return true;
    }
    public static boolean helper(char[][] board){

        for (int i=0;i<9;i++){
            for (int j=0;j<9;j++){
                if(board[i][j]=='.'){
                    for (char num='1';num<='9';num++){
                        if(isValid(board,i,j,num)){
                            board[i][j]=num;
                            //开始下一个位置的选择
                            //helper(board);
                            if(helper(board))
                            {
//                                System.out.println(i+" "+j);
                                return true;
                            }
                            //下一个情况全部遍历结束,没有合适的,则把当前位置 置.
                            board[i][j]='.';
                        }
                    }
                    //这里,说明当前的位置(i,j)没有合适的值插入,回溯到前一层的调用
                    return false;
                }
            }
        }

        printArr(board);
        return true;
    }

测试方法:

    public static void main(String[] args) {
        char[][] board = {
                { '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'}
        };


        System.out.println(helper(board));


    }

需要注意的问题

我之前在回溯代码那一块写的是:

    public static boolean helper(char[][] board){

        for (int i=0;i<9;i++){
            for (int j=0;j<9;j++){
                if(board[i][j]=='.'){
                    for (char num='1';num<='9';num++){
                        if(isValid(board,i,j,num)){
                            board[i][j]=num;
                            //开始下一个位置的选择
                            helper(board);
//                            if(helper(board))
//                            {
//                                System.out.println(i+" "+j);
//                                return true;
//                            }
                            //下一个情况全部遍历结束,没有合适的,则把当前位置 置.
                            board[i][j]='.';
                        }
                    }
                    //这里,说明当前的位置(i,j)没有合适的值插入,回溯到前一层的调用
                    return false;
                }
            }
        }

        printArr(board);
        return true;
    }

结果:
在这里插入图片描述

原因:
递归调用栈,调用到printArr(board)打印最终的数组时,调用栈其实是压满了。。。。。打印数组后,调用了return true(只调用到了这一次true)。之后,helper(board)从最后的i=8,j=6 一个一个出栈
在这里插入图片描述
由于return false语句在return true之前,
在这里插入图片描述
所以最下面的一层(最外层的方法返回了false…)

修改:

                            if(helper(board))
                            {
                                //System.out.println(i+" "+j);
                                return true;
                            }

这样的话,最上层在执行了printArr(board);后返回true,if条件满足,返回true,栈一层一层都返回true。到最后最外层也返回true,满足题意。

运行结果

在这里插入图片描述
在这里插入图片描述

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值