LeetCode 37 解数独 JavaScript 剪枝

138 阅读1分钟

原创 提交时才注意到要 in-place 所以后来打了两层循环给 board 一个个赋值

/**
 * @param {character[][]} board
 * @return {void} Do not return anything, modify board in-place instead.
 */
var solveSudoku = function(board) {
    function check(val, i, j, result) {
        for (let k = 0; k < 9; ++k) {
            // 横向检查
            if (result[i][k] === val) return false;

            // 纵向清理
            if (result[k][j] === val) return false;
        }
        // 小九宫格校验
        const startX = Math.floor(i / 3) * 3;
        const startY = Math.floor(j / 3) * 3;
        for (let p = startX; p < startX + 3; ++p) {
            for (let q = startY;  q < startY + 3; ++q) {
                if (p === i || q === j) continue;
                const tmp = result[p][q];
                if (tmp === val) return false;
            }
        }
        return true;
    }



    function dig(r, data, pointer = 0) {
        const result = r.map((arr) => arr.slice());
        const {
            posses,
            i,
            j,
        } = data[pointer];

        if (r[i][j] !== '.') {
            dig(result, data, pointer + 1);
            return;
        }

        for (let t = 0; t < posses.length; ++t) {
            const v = posses[t];
            if (check(v, i, j, result)) { // 初步检测通过
                result[i][j] = v;
                if (pointer === data.length - 1) { // 这波假设成功了
                    for (let ii = 0; ii < 9; ++ii) {
                        for (let jj = 0; jj < 9; ++jj) {
                            board[ii][jj] = result[ii][jj];
                        }
                    }
                    throw new Error();
                    return;
                }
                dig(result, data, pointer + 1);
            }
        }
    }




    const data = [];
    // 第一波循环,预处理好可选项
    for (let i = 0; i < 9; ++i) {
        for (let j = 0; j < 9; ++j) {
            const char = board[i][j];
            let posses = '123456789';
            if (char === '.') { // 未确定
                for (let k = 0; k < 9; ++k) {
                    // 横向清理
                    const tmp = board[i][k];
                    if (tmp !== '.') {
                        posses = posses.replace(tmp, '');
                    }
                    // 纵向清理
                    const tmp2 = board[k][j];
                    if (tmp2 !== '.') {
                        posses = posses.replace(tmp2, '');
                    }
                }
                // 小九格清理
                const startX = Math.floor(i / 3) * 3;
                const startY = Math.floor(j / 3) * 3;
                for (let p = startX; p < startX + 3; ++p) {
                    for (let q = startY;  q < startY + 3; ++q) {
                        if (p === i || q === j) continue;
                        const tmp = board[p][q];
                        if (tmp !== '.') {
                            posses = posses.replace(tmp, '');
                        }
                    }
                }
                if (posses.length !== 1) {
                    data.push({
                        char,
                        posses,
                        i,
                        j,
                    });
                } else {
                    board[i][j] = posses[0];
                }
            }
        }
    }
    try {
        dig(board, data);
    } catch (e) {
        return;
    }
};