1. 程式人生 > >[LeetCode] 37. 解數獨

[LeetCode] 37. 解數獨

pri 序列 列塊 找到 解法 arraylist thumb 進步 檢查

題目鏈接 : https://leetcode-cn.com/problems/sudoku-solver/

題目描述:

編寫一個程序,通過已填充的空格來解決數獨問題。

一個數獨的解法需遵循如下規則

  1. 數字 1-9 在每一行只能出現一次。

  2. 數字 1-9 在每一列只能出現一次。

  3. 數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。

    空白格用 ‘.‘ 表示。

示例:

技術分享圖片

一個數獨。

技術分享圖片

答案被標成紅色。

Note:

  • 給定的數獨序列只包含數字 1-9 和字符 ‘.‘
  • 你可以假設給定的數獨只有唯一解。
  • 給定數獨永遠是 9x9 形式的。

思路:

思路1:

用一句話解釋:不停的試數

詳細解釋:對於空位置,從數字1

9去試數,

如何判斷這個是否是這個數,就是通過數獨的規則,行列塊出現相同的數字就不行.

所以,我們就可以通過回溯方法去解決,詳細解釋寫在代碼裏!

因為我不太擅長 Java 只能通過與 Python 方式寫出來,如果有更好的方式可以提供給我,謝謝 !

思路2:

有種在線方法,沒看懂,留個坑

未完待續...


關註我的知乎專欄,了解更多的解題技巧,大家共同進步!

代碼:

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        # 把所有沒填數字的位置找到
        all_points = []
        for i in range(9):
            for j in range(9):
                if board[i][j] == ".":
                    all_points.append([i, j])
        # check函數是為了檢查是否在point位置k是合適的
        def check(point, k):
            row_i = point[0]
            col_j = point[1]
            for i in  range(9):
                # 檢查 行
                if i != row_i and board[i][col_j] == k:
                    return False
                # 檢查 列
                if i != col_j and board[row_i][i] == k:
                    return False
            # 檢查塊
            for i in range(row_i//3*3 , row_i//3*3+3):
                for j in range(col_j//3*3, col_j//3*3+3):
                    if i != row_i and j != col_j and board[i][j] == k:
                        return False
            
            return True
        
        def backtrack(i):
            # 回溯終止條件
            if i == len(all_points):
                return True
            for j in range(1, 10):
                # 檢查是否合適
                if check(all_points[i],str(j)):
                    # 合適就把位置改過來
                    board[all_points[i][0]][all_points[i][1]] = str(j)
                    if backtrack(i+1): # 回溯下一個點
                        return True
                    board[all_points[i][0]][all_points[i][1]] = "."# 不成功把原來改回來
            return False
        
        backtrack(0)
class Solution {
    public void solveSudoku(char[][] board) {
        if (board == null || board.length == 0) return;
        List<int[]> all_points = new ArrayList<>();

        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] == '.') all_points.add(new int[]{i, j});
            }
        }
        backtrack(0, all_points, board);
    }

    private boolean backtrack(int i, List<int[]> all_points, char[][] board) {
        if (i == all_points.size()) return true;
        for (char c = '1'; c <= '9'; c++) {
            if (check(all_points.get(i), c, board)) {
                board[all_points.get(i)[0]][all_points.get(i)[1]] = c;
                if (backtrack(i + 1, all_points, board)) return true;
                board[all_points.get(i)[0]][all_points.get(i)[1]] = '.';

            }
        }
        return false;

    }

    private boolean check(int[] ints, char c, char[][] board) {
        int row_i = ints[0];
        int col_j = ints[1];
        for (int i = 0; i < 9; i++) {
            if (i != row_i && board[i][col_j] == c) return false;
            if (i != col_j && board[row_i][i] == c) return false;
        }
        for (int i = row_i / 3 * 3; i < row_i / 3 * 3 + 3; i++) {
            for (int j = col_j / 3 * 3; j < col_j / 3 * 3 + 3; j++) {
                if (i != row_i && j != col_j && board[i][j] == c) return false;
            }
        }

        return true;
    }
}

[LeetCode] 37. 解數獨