题解 | #Sudoku#

Sudoku

https://www.nowcoder.com/practice/78a1a4ebe8a34c93aac006c44f6bf8a1

【Java实现】
使用回溯法,类似“N皇后”问题,具体思路和代码如下,欢迎大家交流讨论。
import java.util.*;

public class Main {
    /*
    一开始没什么思路,参考了题解:https://blog.nowcoder.net/n/9e0bf935707e492387116ee8c3e1c933
    (其实我的解法和这个题解差别挺大的,但确实有受到启发)
    
    思路:回溯法
    (思路有点像“N皇后”问题)
    总体思路:递归遍历每个空格,for循环尝试填入1-9
    
    全局变量:
        - int[][] map = new int[9][9]: 9x9的棋盘
        - boolean hasFinish:是否已正确填充所有空格
        - List<List<Integer>> spaces: 二维列表,存放所有空格的坐标
    步骤:
    1. 初始化棋盘,并记录所有空格的坐标(i,j),存至二维列表spaces中
    
    2. 回溯函数(参数:下标index,即当前要填充的空格在spaces的下标){
        终止条件:已遍历完所有空格(即index == spaces.size()),
                    并将hasFinish设为true
        for (遍历val:1-9,作为填入空格的值) {
            if (当前空格可以填入val) {
                填充空格;
                递归调用回溯函数(下一个空格下标:index+1);
                if (hasFinish) {
                    return;
                }
                将空格值还原为0; // 回溯,撤销修改
            }
        }
    }
    */
    
    //=======代码如下:========
    // 9*9的棋盘
    static int[][] map = new int[9][9];
    // 二维列表,存放所有空格的坐标,如:[[0,0], [8,0]]
    static List<List<Integer>> spaces = new ArrayList<>();
    // 标记变量:是否已正确填充所有空格
    static boolean hasFinish = false;
    
    public static void main(String[] args) {
        // 初始化棋盘
        Scanner in = new Scanner(System.in);
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                map[i][j] = in.nextInt();
                // 将空格的坐标记录到spaces中
                if (map[i][j] == 0) {
                    spaces.add(Arrays.asList(i,j));
                }
            }
        }
        // 调用回溯函数
        backtrack(0);
        // 输出填充完毕后的棋盘
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                System.out.print(map[i][j] + " ");
            }
            System.out.println();
        }
    }
    
    /*
     * 回溯函数
     *     参数:index 当前要填充的空格在spaces的下标
     */
    static void backtrack(int index) {
        if (index == spaces.size()) {
            hasFinish = true;
            return;
        }
        // 获取空格的坐标
        List<Integer> space = spaces.get(index);
        int row = space.get(0);
        int col = space.get(1);
        // 遍历填入空格的可能值:1-9
        for (int val = 1; val <= 9; val++) {
            if (passCheck(row, col, val)) {
                map[row][col] = val;
                backtrack(index + 1);
                if (hasFinish) {
                    return;
                }
                map[row][col] = 0;
            }
        }
    }
    
    // 检测在map[row][col] 填入 val,是否满足数独条件
    static boolean passCheck(int row, int col, int val) {
        // 检测所在行
        for (int i = 0; i < 9; i++) {
            if (map[row][i] == val)
                return false;
        }
        
        // 检测所在列
        for (int i = 0; i < 9; i++) {
            if (map[i][col] == val)
                return false;
        }
        
        // 检测所在3*3小宫格
        int rowStart = row / 3 * 3; // 小宫格的行的最小值
        int colStart = col / 3 * 3; // 小宫格的列的最小值
        for (int i = rowStart; i < rowStart + 3; i++) {
            for (int j = colStart; j < colStart + 3; j++) {
                if (map[i][j] == val)
                    return false;
            }
        }
        // 通过所有检测
        return true;
    }
}



#华为机试##笔试刷题#
全部评论

相关推荐

牛舌:如果我不想去,不管对方给了多少,我一般都会说你们给得太低了。这样他们就会给下一个offer的人更高的薪资了。
点赞 评论 收藏
分享
评论
2
5
分享
牛客网
牛客企业服务