美文网首页
LeetCode No.36 Valid Sudoku | #H

LeetCode No.36 Valid Sudoku | #H

作者: wxqyppqm | 来源:发表于2016-11-15 00:33 被阅读0次

    Q:

    Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules.
    The Sudoku board could be partially filled, where empty cells are filled with the character '.'.


    Note:A valid Sudoku board (partially filled) is not necessarily solvable. Only the filled cells need to be validated.

    A:

    这个题目并不是要找数独unfilled区域的solution,而是要check每个filled cells是否valid。

    public boolean isValidSudoku(char[][] board) {
        for(int i = 0; i<9; i++){
            HashSet<Character> rows = new HashSet<Character>();  //注释1
            HashSet<Character> columns = new HashSet<Character>();  //注释4
            HashSet<Character> cube = new HashSet<Character>();
    
            for (int j = 0; j < 9;j++){
                if(board[i][j]!='.' && !rows.add(board[i][j]))  //注释2
                    return false;
    
                if(board[j][i]!='.' && !columns.add(board[j][i]))
                    return false;
    
                int RowIndex = 3*(i/3);   //注释3
                int ColIndex = 3*(i%3);
    
                if(board[RowIndex + j/3][ColIndex + j%3]!='.' 
                       && !cube.add(board[RowIndex + j/3][ColIndex + j%3]))
                    return false;
            }
        }
        return true;
    }
    

    注释1:

    为什么类型里要用Character,不可以写成char?
    正如Integer之于int,char是基本数据类型(primitive type),Character是包装类型(Wrapper Classes,也就是类,实例化出来的叫对象),其中还涉及到自动封箱(Autoboxing),自动拆解(extracts):

    example 1:
    int t = 10; Integer t1 = t; //自动封箱

    Integer t = new Integer(10); int t1 = t ; //自动解封

    example 2:
    Interger = obj1; int num1 = 69; obj1 = num1; //自动封箱

    Integer obj2 = new Integer (69); int num2; num2 = obj2; //自动解封

    初次之外很重要的一点,Character作为char的包装类,作为一个类,它提供了很多方法。比如当我们使用HashSet.add()这个方法时,设计到object.equals()等方法,所以包装类的意义就体现出来了。

    还有个情况,就是在数据类型不统一的时候,在操作数据的时候容易引起错误,报出“java.lang.ClassCastException”,比如Integer类型冲突了String,通过泛型,也可以进行一个限制,参考(http://www.cnblogs.com/lwbqqyumidi/p/3837629.html)。


    注释2:

    先来看一下 java.util.HashSet.add() HashSet API方法:

    public boolean add (E e)
    Adds the specified element to this set if it is not already present. More formally, adds the specified element e to this set if this set contains no element e2 such that (e==null ? e2==null : e.equals(e2)). If this set already contains the element, the call leaves the set unchanged and returns false.
    Specified by:
    add in the interface Collection<E>
    add in interface Set<E>
    Overrides:
    add in class AbstractCollection<E>
    Returns:
    true if this set did not already contain the specified element

    由此可知,!rows.add(board[i][j])表达的意思是当要加入新的数字时,如果不成功,说明matrix里已经存在了,那么这时出现了重复的值,要返回false,但!之后,返回true。如果那个cell的值也不是'.',说明那个cell是有数字的。逻辑与(&&)操作之后,true && true,则判断条件成立,return false

    HashSet vs HashMap
    HashSet 实现了Set接口。不允许重复的值。 .add()
    HashMap实现了Map接口。不允许重复的键。.put()

    Map接口有两个基本的实现,HashMap和TreeMap。TreeMap保存了对象的排列次序,而HashMap则不能。HashMap允许键和值为null。HashMap是非synchronized的。

    HashMap <Key, Value>,而我们这里参数进来其实不需要键值,使用Character封装类,匹配parameter char[][] board就好。

    HashSet类维护了一个HashMap引用作为自己的成员变量:
    public HashSet() { map = new HashMap<E,Object>(); }
    HashSet源码分析:http://blog.chinaunix.net/uid-26864892-id-3167656.html


    注释3:

    @jaqenhgar 解释了这里运算背后的逻辑:

    0,0, 0,1, 0,2; < --- 3 Horizontal Steps followed by 1 Vertical step to next level.
    1,0, 1,1, 1,2; < --- 3 Horizontal Steps followed by 1 Vertical step to next level.
    2,0, 2,1, 2,2; < --- 3 Horizontal Steps.
    And so on...But, the j iterates from 0 to 9.
    But we need to stop after 3 horizontal steps, and go down 1 step vertical.

    Use % for horizontal traversal. Because % increments by 1 for each j : 0%3 = 0 , 1%3 = 1, 2%3 = 2, and resets back. So this covers horizontal traversal for each block by 3 steps.
    Use / for vertical traversal. Because / increments by 1 after every 3 j: 0/3 = 0; 1/3 = 0; 2/3 =0; 3/3 = 1.

    So far, for a given block, you can traverse the whole block using just j.
    But because j is just 0 to 9, it will stay only first block. But to increment block, use i. To move horizontally to next block, use % again : ColIndex = 3 * (i%3) (Multiply by 3 so that the next block is after 3 columns. Ie 0,0 is start of first block, second block is 0,3 (not0,1);
    Similarly, to move to next block vertically, use / and multiply by 3 as explained above. Hope this helps.

    逐个block traversal

    相关文章

      网友评论

          本文标题:LeetCode No.36 Valid Sudoku | #H

          本文链接:https://www.haomeiwen.com/subject/znzhpttx.html