先看下交集
Integer[] intersection(int[] a, int[] b) {
if (a == null || b == null || a.length == 0 || b.length == 0) {
return new Integer[0];
}
List list = new LinkedList<>();
int i = 0, j = 0, alen = a.length, blen = a.length;
while (i < alen && j < blen) {
if (a[i] == b[j]) {
list.add(a[i]);
while (++i < alen && a[i] == a[i - 1]) ;
while (++j < blen && b[j] == b[j - 1]) ;
} else if (a[i] < b[j]) {
while (++i < alen && a[i] == a[i - 1]) ;
} else {
while (++j < blen && b[j] == b[j - 1]) ;
}
}
return list.toArray(new Integer[0]);
}
再看并集,这个要复杂一些。容易想到的算法是,将两个数组merge,得到一个新的有序数组,然后去重即可。但后来发现,在merge的时候就可以去重了。
Integer[] union(int[] x, int[] y) {
int[] a = x == null ? new int[0] : x;
int[] b = y == null ? new int[0] : y;
LinkedList list = new LinkedList<>();
int i = 0, j = 0, alen = a.length, blen = b.length;
while (i < alen || j < blen) {
if (i < alen && j >= blen) {
if (list.isEmpty() || a[i] > list.getLast()) {
list.add(a[i]);
}
while (++i < alen && a[i] == a[i - 1]) ;
} else if (j < blen && i >= alen) {
if (list.isEmpty() || b[j] > list.getLast()) {
list.add(b[j]);
}
while (++j < blen && b[j] == b[j - 1]) ;
} else {
if (a[i] < b[j]) {
list.add(a[i]);
list.add(b[j]);
} else if (a[i] > b[j]) {
list.add(b[j]);
list.add(a[i]);
} else {
list.add(a[i]);
}
while (++i < alen && a[i] == a[i - 1]) ;
while (++j < blen && b[j] == b[j - 1]) ;
}
}
return list.toArray(new Integer[0]);
}
首先注意一个技巧,int[] a = x == null ?new int[0] : x ,将null转换成空数组,这样就是用下面的代码,不然要专门写一段逻辑。
这里的merge和归并排序的merge有几点不同:
由于重复元素,i 和 j 的递增使用while循环。
当一个数组遍历完毕后,还需要考虑重复元素。
上面的代码略显啰嗦,可以简化:
Integer[] union(int[] x, int[] y) {
int[] a = x == null ? new int[0] : x;
int[] b = y == null ? new int[0] : y;
LinkedList list = new LinkedList<>();
int i = 0, j = 0, alen = a.length, blen = b.length;
while (i < alen || j < blen) {
if (j >= alen || (i < alen && a[i] <= b[j])) {
if (list.isEmpty() || a[i] > list.getLast()) {
list.add(a[i]);
}
//i++;
while (++i < alen && a[i] == a[i - 1]) ;
} else {
if (list.isEmpty() || b[j] > list.getLast()) {
list.add(b[j]);
}
//j++;
while (++j < blen && b[j] == b[j - 1]) ;
}
}
return list.toArray(new Integer[0]);
}
其中注释那行可以和while那行互换。
现在看来,没有必要非要使用链表,使用ArrayList也可以快的查看。
2019-03-20阅:
无论是在面试中还是工作中,都不要写过于复杂的代码,因为成本高、易出错。简简单单就是好的。
Integer[] intersection(int[] a, int[] b) {
if (a == null || b == null || a.length == 0 || b.length == 0) {
return new Integer[0];
}
Deque deque = new LinkedList<>();
int i = 0, j = 0, alen = a.length, blen = a.length;
while (i < len && j < len) {
if (a[i] > b[j]) {
j++;
} else if (a[i] < b[j]) {
i++;
} else {
if (deque.isEmpty() || deque.getLast() != a[i]) {
deque.add(a[i]);
}
i++;
j++;
}
}
return deque.toArray(new Integer[0]);
}
Integer[] union(int[] x, int[] y) {
int[] a = x == null ? new int[0] : x;
int[] b = y == null ? new int[0] : y;
Deque deque = new LinkedList<>();
int i = 0;
int j = 0;
int alen = a.length;
int blen = b.length;
int key;
while (i < alen || j < blen) {
if (j >= blen || (i < alen && a[i] <= b[j])) {
key = a[i++];
} else {
key = b[j++];
}
if (deque.isEmpty() || deque.getLast() != key) {
deque.add(key);
}
}
return deque.toArray(new Integer[0]);
}
这次已经使用了Deque,比LinkedList要优雅些。