晚上闲来无事,想起前两天查资料时候,看到别人一篇博客标题关于数组的交集和并集,晚上也随便写写,权当督促自己坚持经常练习练习写写小Demo。如下,先来一段求有序数组的交集的代码,代码如下:
public static List<Integer> getIntersectionSorted(int[] a,int[] b){
if(a == null || b == null)
throw new NullPointerException("Array is Empty");
List<Integer> mixList = new ArrayList<Integer>();
int i = 0;
int j = 0;
while(i < a.length && j < b.length){
if(a[i] == b[j]){
mixList.add(a[i]);
//当前结点值相同,所以下次判断结点,先往前移动一次再说
do{
i++;
}while(i < a.length -1 && a[i] == a[i+1]);//当前判断结点下一个结点值是否等于前一个,如果等于避免无谓的再一圈循环,直接移动到下一个结点
do{
j++;
} while(j < b.length -1 && b[j] == b[j+1]);
continue;
}else if(a[i] > b[j]){
j++;
continue;
}else if(a[i] < b[j]){
i++;
continue;
}
}
return mixList;
}
由以上代码我们知道上面的求法最差时间负责度为O(m+n)。如果我们的数组没有排序,以上的方式肯定行不通,下面贴出求两无序数组的并集的代码,代码如下:
public static List<Integer> getIntersectionNotSortedUsingWhile(int[] a,int[] b){
if(a == null || b == null)
throw new NullPointerException("Array is Empty");
List<Integer> mixList = new ArrayList<Integer>();
int startIndex = 0;
int i = 0;
while(i<b.length){
int temp = b[i];
int j = startIndex;
while(j <a.length){
while(j < a.length -1 && a[j] == a[j+1]){
j++;
}
if(a[j] == temp){//当前判断结点下一个结点值是否等于前一个,如果等于避免无意义的移动
mixList.add(temp);
swap(a,startIndex,j); //此处操作:将数组元素分成两部分,一部分已经判断过的元素,每次元素判断过后,将该元素移动到判断过的部分,下次判断从未判断部分开始继续判断
//因为已经添加到mixList的元素没有必要再下一次循环去判断的必要了。(类似插入排序的意思)
startIndex++;
break;
}
j++;
}
i++;
}
return mixList;
}
public static List<Integer> getIntersectionNotSortedUsingFor(int[] a,int[] b){
if(a == null || b == null)
throw new NullPointerException("Array is Empty");
List<Integer> mixList = new ArrayList<Integer>();
int startIndex = 0;
for(int i = 0;i<b.length;i++){
int temp = b[i];
for(int j = startIndex;j<a.length;j++){
while(j < a.length -1 && a[j] == a[j+1]){//当前判断结点下一个结点值是否等于前一个,如果等于避免无意义的移动
j++;
}
if(a[j] == temp){
mixList.add(temp);
swap(a,startIndex,j);//同上
startIndex++;
break;
}
}
}
return mixList;
}
public static void swap(int[] a,int m,int n){
int temp = a[m];
a[m] = a[n];
a[n] = temp;
}
以上代码可知,以上算法的效率可能没有达到最优,自己感觉效率还没有那么差吧,稍微借鉴了下插入排序做了小小的优化,时间复杂度也相对稳定。
下面把自己求两个数组的并集的练习也贴出来,有什么地方不对,还希望园友指出。先求有序两个数组的并集代码如下:
public static List<Integer> getUnionSetSorted(int[] a,int[] b){
if(a == null || b == null)
throw new NullPointerException("Array is Empty");
List<Integer> mixList = new ArrayList<Integer>();
int i = 0,j = 0;
while(i < a.length && j < b.length){
if(a[i] == b[j]){
mixList.add(a[i]);
i++;
while(i< a.length -1 && a[i] == a[i+1]){ //判断当前元素和下一个元素是否重复,重复元素直接前进一位
i++;
}
j++;
while(j< b.length -1 && b[j] == b[j+1]){
j++;
}
}else if(a[i] < b[j]){
mixList.add(a[i]);
i++;
while(i< a.length -1 && a[i] == a[i+1]){
i++;
}
}else if(a[i] > b[j]){
mixList.add(b[j]);
j++;
while(j< b.length -1 && b[j] == b[j+1]){
j++;
}
}
}
while(i <a.length){ //判断合并循环退出时,a数组还没有添加完
mixList.add(a[i]);
i++;
while(i< a.length -1 && a[i] == a[i+1]){
i++;
}
}
while(j < b.length){//同上
mixList.add(b[j]);
j++;
while(i< a.length -1 && a[i] == a[i+1]){
i++;
}
}
return mixList;
}
该代码的最差时间负责度也为O(M + N)。
下面我们求两个无序数组的并集的实现,代码如下:
public static List<Integer> getUnionSetNotSorted(int[] a,int[] b){
if(a == null || b == null)
throw new NullPointerException("Array is Empty");
List<Integer> mixList = new ArrayList<Integer>();
for(int i = 0;i<a.length;i++){
if(!mixList.contains(a[i])){
mixList.add(a[i]);
}
}
for(int i = 0;i<b.length;i++){
if(!mixList.contains(b[i])){
mixList.add(b[i]);
}
}
return mixList;
}
该代码的实现时间负责度为O(n2)。最后求两个无序的数组的并集代码的效率还有待提高,暂时没有想到效率更高的实现,路过的园友还望不吝指教。