Leetcode 37. Sudoku Solver 递归与非递归两种写法

本文介绍了一种使用深度优先搜索和回溯法解决数独问题的算法。通过将数独视为81个点的序列,从第一个点开始,寻找合法的填数字位置,遇到障碍则回溯,直至找到解决方案。

题目:

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

A sudoku solution must satisfy all of the following rules:

  1. Each of the digits 1-9 must occur exactly once in each row.
  2. Each of the digits 1-9 must occur exactly once in each column.
  3. Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.

Empty cells are indicated by the character '.'.


A sudoku puzzle...


...and its solution numbers marked in red.

Note:

  • The given board contain only digits 1-9 and the character '.'.
  • You may assume that the given Sudoku puzzle will have a single unique solution.
  • The given board size is always 9x9.

题意:

该题题意理解起来很简单,就是做一个9x9的数独题,每行每列只出现1-9数字各一次,每个小九宫格出现1-9数字各一次。

题目中,给定输入,数独表中空缺的填入字符'.'。

 

解法:

思路是运用深度优先遍历加上回溯法来进行解答。将整个9x9的表看成81个点的序列,由第一个点出发,寻找可以填入的值(遇到表中固定值时跳过),一步一步进行,如果遇到无法走通的地方,进行回溯。一直进行以上操作,直到走到81格。

 

非递归:

class Solution {
    public void solveSudoku(char[][] board) {
        int d=0,k=0,row=0,col=0,start=0;
        int []flag=new int[81];
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                if(board[i][j]=='.') flag[k]=1;
                else flag[k]=0;
                k++;
            }
        }
        while(d<81){
            if(flag[d]==0) {
                d++;
                continue;
            }
            row=d/9;
            col=d%9;
            if(board[row][col]=='.'){
                start=1;
            }
            else{
                start=board[row][col]-'0'+1;
            }
            for(k=start;k<=9;k++){
                if(valid(board,row,col,(char)(k+'0'))==true) break;
            }
            if(k==10){    //回溯
                 board[row][col]='.';
                 for(int h=d-1;h>=0;h--){
                     if(flag[h]==1) {
                         d=h;
                         break;
                     }
                 }
            }
            else{
                board[row][col]=(char)(k+'0');
                d++;
            }
        }
        
    }
    public static boolean valid(char[][] board,int i,int j,char temp){ //判断填入值是否有效
        for(int x=0;x<9;x++){
            if(board[i][x]==temp||board[x][j]==temp) return false;
        }
        int bi=i/3;
        int bj=j/3;     //计算属于哪个小九宫格
        for(int x=bi*3;x<bi*3+3;x++){
            for(int y=bj*3;y<bj*3+3;y++){
                if(board[x][y]==temp) return false;
            }
        }
        return true;
    }
}

递归法:

public class Solution {
    public void solveSudoku(char[][] board) {
        dfs(board,0);
    }
    private boolean dfs(char[][] board, int d) {
        if (d==81) return true; //found solution
        int i=d/9, j=d%9;
        if (board[i][j]!='.') return dfs(board,d+1);//prefill number skip
        
        boolean[] flag=new boolean[10];
        validate(board,i,j,flag);
        for (int k=1; k<=9; k++) {
            if (flag[k]) {
                board[i][j]=(char)('0'+k);
                if (dfs(board,d+1)) return true;
            }
        }
        board[i][j]='.'; //if can not solve, in the wrong path, change back to '.' and out
        return false;
    }
    private void validate(char[][] board, int i, int j, boolean[] flag) {
        Arrays.fill(flag,true);
        for (int k=0; k<9; k++) {
            if (board[i][k]!='.') flag[board[i][k]-'0']=false;
            if (board[k][j]!='.') flag[board[k][j]-'0']=false;
            int r=i/3*3+k/3;
            int c=j/3*3+k%3;
            if (board[r][c]!='.') flag[board[r][c]-'0']=false;
        }
    }
}

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值