leetcode37. 解数独

96 篇文章 1 订阅
81 篇文章 1 订阅

https://leetcode-cn.com/problems/sudoku-solver/submissions/
这道题,我用的是我平时解数独的方法去做的
没一个空格,通过横、纵、小区域来判断这个空格有哪几个可能性,如果只有一个可能,直接填入
如果删选发现所有的格子都是多种可能,那就选一个可能性少的(2选1),填入一个值后进行假设猜想,如果失败,换一个值测试

我就把我做题的逻辑,写成了代码

为了方便理解和自己写代码,加了两个类
NodeB:用于保存剩余值,比如某一行已经有了几个值,把剩余的值保存(使用在某一行、某一列、某一个3X3区域)
NodeC:格子,用于保存可能的可能值

代码:

public void solveSudoku(char[][] board) {
    //每一横的剩余数
    NodeB[] rNnodes = new NodeB[9];
    //每一纵的剩余数
    NodeB[] cNnodes = new NodeB[9];
    //每一个小区域的剩余数
    NodeB[] hNnodes = new NodeB[9];
    for (int i = 0; i < 9; i++) {
        rNnodes[i] = new NodeB();
        cNnodes[i] = new NodeB();
        hNnodes[i] = new NodeB();
    }
    Set<NodeC> nodeCs = new HashSet<>();
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            if (board[i][j] == '.') {
                nodeCs.add(new NodeC(i, j));
            } else {
                int v = board[i][j] - '0';
                //当一个格子有值时,横、纵、小区域的剩余数移除
                rNnodes[i].remove(v);
                cNnodes[j].remove(v);
                hNnodes[(i / 3) * 3 + j / 3].remove(v);
            }
        }
    }
    while (true) {
        Set<NodeC> removeSet = new HashSet<>();
        for (NodeC nodeC : nodeCs) {
            NodeB nr = rNnodes[nodeC.r];
            NodeB nc = cNnodes[nodeC.c];
            NodeB nh = hNnodes[(nodeC.r / 3) * 3 + nodeC.c / 3];
            nodeC.setVs(nr, nc, nh);
            if (nodeC.size == 1) {
                //只有一个可能时,填入值,移除横、纵、小区域可能性
                removeSet.add(nodeC);
                board[nodeC.r][nodeC.c] = (char) (nodeC.vs[0] + '0');
                nr.remove(nodeC.vs[0]);
                nc.remove(nodeC.vs[0]);
                nh.remove(nodeC.vs[0]);
            }
        }
        nodeCs.removeAll(removeSet);
        if (nodeCs.size() == 0) {
            break;
        }
        if (removeSet.size() == 0) {
            //循环一次,每一可填入值的时候,开始试
            NodeC node = nodeCs.iterator().next();
            nodeCs.remove(node);
            for (int i = 0; i < node.size; i++) {
                char[][] cc = doTest(copyOf(rNnodes), copyOf(cNnodes), copyOf(hNnodes), copyOf(board), copyOf(nodeCs), node.r, node.c, node.vs[i]);
                if (cc != null) {
                    for (int k = 0; k < board.length; k++) {
                        for (int j = 0; j < board[0].length; j++) {
                            board[k][j] = cc[k][j];
                        }
                    }
                }
            }
            return;
        }
    }

}

//假设操作
private char[][] doTest(NodeB[] rNnodes, NodeB[] cNnodes, NodeB[] hNnodes, char[][] board, Set<NodeC> nodeCs, int r, int c, int v) {
    board[r][c] = (char) (v + '0');
    rNnodes[r].remove(v);
    cNnodes[c].remove(v);
    hNnodes[(r / 3) * 3 + c / 3].remove(v);
    while (true) {
        Set<NodeC> removeSet = new HashSet<>();
        for (NodeC nodeC : nodeCs) {
            NodeB nr = rNnodes[nodeC.r];
            NodeB nc = cNnodes[nodeC.c];
            NodeB nh = hNnodes[(nodeC.r / 3) * 3 + nodeC.c / 3];
            nodeC.setVs(nr, nc, nh);
            if (nodeC.size == 1) {
                removeSet.add(nodeC);
                board[nodeC.r][nodeC.c] = (char) (nodeC.vs[0] + '0');
                nr.remove(nodeC.vs[0]);
                nc.remove(nodeC.vs[0]);
                nh.remove(nodeC.vs[0]);
            }
            //每一可能性,说明假设失败
            if (nodeC.size == 0) {
                return null;
            }
        }
        nodeCs.removeAll(removeSet);
        if (nodeCs.size() == 0) {
            return board;
        }
        if (removeSet.size() == 0) {
            NodeC node = nodeCs.iterator().next();
            nodeCs.remove(node);
            for (int i = 0; i < node.size; i++) {
                char[][] cc = doTest(copyOf(rNnodes), copyOf(cNnodes), copyOf(hNnodes), copyOf(board), copyOf(nodeCs), node.r, node.c, node.vs[i]);
                if (cc != null) {
                    return cc;
                }
            }
            //循环结束还是没有成功的,说明失败
            return null;
        }
    }
}

private NodeB[] copyOf(NodeB[] rNnodes) {
    NodeB[] mNodes = new NodeB[rNnodes.length];
    for (int i = 0; i < rNnodes.length; i++) {
        mNodes[i] = rNnodes[i].copy();
    }
    return mNodes;
}

private char[][] copyOf(char[][] board) {
    char[][] nc = new char[board.length][board[0].length];
    for (int i = 0; i < board.length; i++) {
        for (int j = 0; j < board[0].length; j++) {
            nc[i][j] = board[i][j];
        }
    }
    return nc;
}

private Set<NodeC> copyOf(Set<NodeC> nodeCs) {
    Set<NodeC> nNodeCs = new HashSet<>();
    for (NodeC temp : nodeCs) {
        nNodeCs.add(temp.copy());
    }
    return nNodeCs;
}

class NodeB {
    int[] keys = new int[9];//剩余数数组
    int size;//剩余数的个数

    NodeB() {
        for (int i = 0; i < 9; i++) {
            keys[i] = i + 1;
        }
        size = 9;
    }

    public void remove(int v) {
        for (int i = 0; i < size; i++) {
            if (keys[i] == v) {
                for (int j = i; j < size - 1; j++) {
                    keys[j] = keys[j + 1];
                }
            }
        }
        size--;
        keys[size] = 0;
    }

    public NodeB copy() {
        NodeB nNodeB = new NodeB();
        nNodeB.size = size;
        for (int i = 0; i < 9; i++) {
            nNodeB.keys[i] = keys[i];
        }
        return nNodeB;
    }
}

class NodeC {
    int r;//格子的位置
    int c;
    int[] vs;//可能性的值
    int size;//格子的可能性数

    NodeC(int i, int j) {
        r = i;
        c = j;
    }

    public void setVs(NodeB nr, NodeB nc, NodeB nh) {
        int[] kk = new int[10];
        for (int i = 0; i < nr.size; i++) {
            kk[nr.keys[i]]++;
        }
        for (int i = 0; i < nc.size; i++) {
            kk[nc.keys[i]]++;
        }
        for (int i = 0; i < nh.size; i++) {
            kk[nh.keys[i]]++;
        }
        vs = new int[9];
        size = 0;
        for (int i = 1; i <= 9; i++) {
            if (kk[i] == 3) {
                vs[size++] = i;
            }
        }
    }

    public NodeC copy() {
        NodeC nNodeC = new NodeC(r, c);
        nNodeC.vs = new int[9];
        nNodeC.size = size;
        for (int i = 0; i < size; i++) {
            nNodeC.vs[i] = vs[i];
        }
        return nNodeC;
    }
}

代码执行时间偏长,原因几点
为了方便理解,使用了新的类对象
每一次遍历都是循环,可以改成递归,如某一格修改之后,只需要再判断同行、同列、同区域的
不过,写这些代码就花了两个小时,有空再改吧

leetcode的一些已经写的觉得有意思的其他题目
https://blog.csdn.net/qq_33321609/article/category/9012437
如果有我没有写博客的其他题目需要讨论,欢迎评论,一起探讨

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值