2021.04,準備面試和CCF CSP認證的我準備作一套CCF模擬題,而後就有了此篇博客(x
題目:201912-2 回收站報數
題目截圖:java
第一個想法:讀取每一個垃圾的位置,存入TreeSet中,而後依次取出判斷是否能夠創建回收站和評分(不能夠創建回收站,評分爲-1)。
這時候就有讀者要問了:啊這你爲何要使用TreeSet呢?不使用HashSet呢?
我回答:由於輸出須要順序啊,HashSet輸出是(沒有順序的)不保證有序的,即有可能出現有序可是程序設計不能依賴於此。
讀者:噢,原來如此。
作完題目的我:一看你就是一大段文字不喜歡看(x,題目都沒看清(別罵了,我也是🤡),題目最後的輸出是須要統計每種得分的個數,不須要有序,用HashSet徹底是足夠了。
讀者:WTF,一種植物。node
可是在我看錯題目的解題過程當中(hhh),出現了錯誤,準確的說是TreeSet的使用錯誤,這篇博客記錄一下錯誤和過程。面試
在上述題目中,筆者使用的是TreeSet進行排序,而後每個依次判斷輸出,可是最後輸出的結果所有都是4,全部的垃圾點都是回收站而且評分都是4,即對於任意一個垃圾,周圍8個邊界都存在垃圾。數組
這是我進行判斷而且計算評分的代碼:ide
public static int score(int x, int y, Set<Point1912> set) { if (set.contains(new Point1912(x + 1, y)) && set.contains(new Point1912(x - 1, y)) && set.contains(new Point1912(x, y + 1)) && set.contains(new Point1912(x, y - 1))) { int sum = 0; sum += (set.contains(new Point1912(x + 1, y + 1)) ? 1 : 0); sum += (set.contains(new Point1912(x - 1, y + 1)) ? 1 : 0); sum += (set.contains(new Point1912(x + 1, y - 1)) ? 1 : 0); sum += (set.contains(new Point1912(x - 1, y - 1)) ? 1 : 0); return sum; } else { return -1; } }
座標類函數
class Point1912 { int x = 0; int y = 0; int seq = 0; public Point1912(int x, int y) { this.x = x; this.y = y; } public Point1912(int x, int y, int seq) { this.x = x; this.y = y; this.seq = seq; } @Override public boolean equals(Object obj) { Point1912 p = (Point1912) obj; return x == p.x && y == p.y; } @Override public int hashCode() { return Objects.hash(x, y); } }
TreeSet代碼this
TreeSet<Point1912> set1 = new TreeSet<>(((o1, o2) -> o1.seq - o2.seq));
很明顯,在判斷的代碼中任意的set.contains()都返回了true,可是在座標類中我明確設計了equals和hashCode方法,保證只有座標相等的時候才能返回true。設計
最終的比較源碼,位置在TreeMap.java調試
final Entry<K,V> getEntryUsingComparator(Object key) { @SuppressWarnings("unchecked") K k = (K) key; Comparator<? super K> cpr = comparator; if (cpr != null) { Entry<K,V> p = root; while (p != null) { int cmp = cpr.compare(k, p.key); if (cmp < 0) p = p.left; else if (cmp > 0) p = p.right; else return p; } } return null; }
問題就出如今這裏了,TreeSet.contains()方法最終在這裏進行比較,重點在於該函數使用的是comparator,這個比較器即是TreeMap用於排序的比較器。由於進行判斷的元素seq都是默認值,因此判斷是否存在的函數要麼所有返回false,要麼所有返回true,由於我設置seq默認爲0,TreeSet中必定存在因此contains全爲true。code
使用HashSet存儲座標,同時使用另外一個ArrayList或者數組存儲座標保證順序。
下面是HashSet.contains()方法的內容,位置HashMap.java
final Node<K,V> getNode(int hash, Object key) { Node<K,V>[] tab; Node<K,V> first, e; int n; K k; if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; if ((e = first.next) != null) { if (first instanceof TreeNode) return ((TreeNode<K,V>)first).getTreeNode(hash, key); do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } return null; }
能夠這裏即是採用key.equals的方法進行比較,重寫equals起了做用。
同時這個first instance of TreeNode 能夠看到HashMap中若是同一個桶的元素超過了7個,在Java1.8中就就將鏈表轉換爲了紅黑樹,Node變成了TreeNode。
TreeMap中元素的比較採用的是Comparator,或者是元素實現的Comparable接口;
HashMap中元素的比較即是元素的equals方法。
若是沒看錯題目,估計也沒這茬子事(嚶嚶嚶x.x)