集合中的hashCode和equals方法

在做全排列的題目的時候,有一種是原數組有重複數字,這樣會造成用回溯後得到的結果有重複數組,爲了去重,可以用set存放結果。

47. 全排列 II

給定一個可包含重複數字的序列,返回所有不重複的全排列。

示例:

輸入: [1,1,2]
輸出:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]

————————————————————————————————————————————————————

set添加元素時,第一比較hashCode,第二比較equals方法

如果用數組存放每個結果的話,數組是沒有重寫這兩個方法的

也就是 A={1,2,3},B={1,2,3}

A.equals(B) 是false

可以用Arrays.equals(A,B),比較,這樣就是true。

 

如果用集合存放結果的話,比如用ArrayList,需要考慮下面幾個問題:

1 首先查看ArrayList的hashCode()和equals方法,看下源碼:

   public int hashCode() {
        int hashCode = 1;
        for (E e : this)
            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
        return hashCode;
    }

也就是說這個數組的hashCode是和每個對象的hashCode有關的。

   public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof List))
            return false;

        ListIterator<E> e1 = listIterator();
        ListIterator<?> e2 = ((List<?>) o).listIterator();
        while (e1.hasNext() && e2.hasNext()) {
            E o1 = e1.next();
            Object o2 = e2.next();
            if (!(o1==null ? o2==null : o1.equals(o2)))
                return false;
        }
        return !(e1.hasNext() || e2.hasNext());
    }

equals方法也是和存儲的數據類型的equals方法相關的。

所以List的比較,是要看存儲元素的類型的,有沒有重寫hashCode和equals

 

以這個題目來說,存放的是Integer元素,可以看源碼,Integer重寫了hashCode和equals

 public static int hashCode(int value) {
        return value;
    }


    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

也就是隻要對應的int值相等,hashCode和equals都相等。

(但是注意地址不一定相等,只有[-128,127]會使用緩存)

所以這個題目,我們可以放心使用ArrayList,然後把結果添加到set,就可以放心去重。

如果你自定義了一個類,沒有重寫hashCode和equals方法,那麼你添加到ArrayList後,這兩個ArrayList一定不相等。

這題代碼如下:

class Solution {
    HashSet<LinkedList<Integer>> set = new HashSet<>();
    LinkedList<Integer> temp = new LinkedList<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        boolean[] visited = new boolean[nums.length];
        permute(nums,0,visited);
        return new ArrayList(set);
          
    }
      public void permute(int[] nums,int k,boolean[] visited) {
          if(k==nums.length) {
              set.add(new LinkedList(temp));
              return;
          }
          for(int i =0;i<nums.length;i++) {
              if(!visited[i]) {
               temp.add(nums[i]);
               visited[i] = true;
               permute(nums,k+1,visited);
               visited[i] = false;
               temp.removeLast(); 
              }
          }      
 }
}

這個題還有個姐妹題:

面試題38. 字符串的排列

輸入一個字符串,打印出該字符串中字符的所有排列。

你可以以任意順序返回這個字符串數組,但裏面不能有重複元素。

 

示例:

輸入:s = "abc"
輸出:["abc","acb","bac","bca","cab","cba"]

 

同理,無論是使用StringBuilder還是String,都重寫了hashcode和equals,比較是否相等,都只和本身元素內容有關而與地址無關,可以放心地使用set去重。

 public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
   public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章