LeetCode No.36 Valid Sudoku | #HashSet #Wrapper Classes

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:

這個題目并不是要找數(shù)獨(dú)unfilled區(qū)域的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是基本數(shù)據(jù)類型(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; //自動解封

初次之外很重要的一點(diǎn),Character作為char的包裝類,作為一個類,它提供了很多方法。比如當(dāng)我們使用HashSet.add()這個方法時,設(shè)計到object.equals()等方法,所以包裝類的意義就體現(xiàn)出來了。

還有個情況,就是在數(shù)據(jù)類型不統(tǒng)一的時候,在操作數(shù)據(jù)的時候容易引起錯誤,報出“java.lang.ClassCastException”,比如Integer類型沖突了String,通過泛型,也可以進(jìn)行一個限制,參考(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])表達(dá)的意思是當(dāng)要加入新的數(shù)字時,如果不成功,說明matrix里已經(jīng)存在了,那么這時出現(xiàn)了重復(fù)的值,要返回false,但!之后,返回true。如果那個cell的值也不是'.',說明那個cell是有數(shù)字的。邏輯與(&&)操作之后,true && true,則判斷條件成立,return false

HashSet vs HashMap
HashSet 實現(xiàn)了Set接口。不允許重復(fù)的值。 .add()
HashMap實現(xiàn)了Map接口。不允許重復(fù)的鍵。.put()

Map接口有兩個基本的實現(xiàn),HashMap和TreeMap。TreeMap保存了對象的排列次序,而HashMap則不能。HashMap允許鍵和值為null。HashMap是非synchronized的。

HashMap <Key, Value>,而我們這里參數(shù)進(jìn)來其實不需要鍵值,使用Character封裝類,匹配parameter char[][] board就好。

HashSet類維護(hù)了一個HashMap引用作為自己的成員變量:
public HashSet() { map = new HashMap<E,Object>(); }
HashSet源碼分析:http://blog.chinaunix.net/uid-26864892-id-3167656.html


注釋3:

@jaqenhgar 解釋了這里運(yùn)算背后的邏輯:

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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗。 張土汪:刷leetcod...
    土汪閱讀 12,921評論 0 33
  • 五更寒夜炊煙升,淡淡粥香夢中聞。 未待起身穿衣時,慈母輕輕送食至。 針刺糙手渾不知,夜夜守兒不覺遲。 何待日后功名...
    拾漁閱讀 277評論 0 0
  • 運(yùn)動健身后,我們需要通過食物來給身體補(bǔ)充能量,讓自己恢復(fù)體力,并且緩解疲勞感。 運(yùn)動過后,大家一般都會有不同程度上...
    一顆梧桐樹閱讀 629評論 0 3
  • 這張圖有多少人能看的懂?一般沒有很強(qiáng)鉆研精神的前端開發(fā)者來說,沒個三年工作經(jīng)驗都不能清楚的把這個原理一一道來,想分...
    Ziksang閱讀 492評論 1 6
  • 忙碌的一周 這周感覺時間過的最快。一晃這周都要完了。但人生沒有退路,所以勇往直前吧! 今天的刑事庭審開的很爽,不過...
    徵羽微涼閱讀 229評論 0 0

友情鏈接更多精彩內(nèi)容