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:

这个题目并不是要找数独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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容