在做全排列的题目的时候,有一种是原数组有重复数字,这样会造成用回溯后得到的结果有重复数组,为了去重,可以用set存放结果。
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [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();
}
}
}
}
这个题还有个姐妹题:
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
输入:s = "abc"
输出:["abc","acb","bac","bca","cab","cba"]
同理,String重写了hashCode和equals,比较是否相等,都只和本身元素内容有关而与地址无关,可以放心地使用set去重。
(注意StringBuilder并没有重写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;
}