经典算法之查找重复元素
问题1:有0~99个互不相同的整数,将这些整数放入一个长度为101的数组,数组中剩余的那个元素为0~99中的任意一个,将数组的顺序打乱。
输出:重复的数字。
这里打乱数组用随机数的思路即可,具体在代码里面有注释
方法1:利用for循环和中间变量进行比较,直到找到相同的数。
缺点:效率太低。
方法2:这个方法是利用运算来进行的,相比方法1执行的效率高。
思路:将数组中的所有元素相加,然后再减去0~99的和即为重复的数字
缺点:当数据较多是容器发生数据溢出现象,所以不适合开发使用。
方法3:这个方法是这里我要着重介绍的方法,利用异或运算来找出。
思路:我们知道,异或运算里面有这样一个运算规则,对同一个数异或俩次结果不变,比如a^b^b的结果为a
所以我们可以让数组中的所有元素与0~99作异或运算,这样我们就会得到重复的数字。
具体的代码如下:
/*题目:有0~99的100个数字,各不相同,将其放在一个数组里,数组的长度位101,多余出来的数字是于100个数字中的一个相同,然后
将数字打乱,要求:找出重复的数字*/
public class Demo02{
public static void main(String[]args){
//定义一个数组
int[]array = new int[101];
//为数组添加元素
for(int i=0;i<100;i++){
array[i] = i;
}
array[100] = 38;//定义重复元素为38
for(int i=0;i<100;i++){
System.out.print(array[i]+"\t");
}
//利用随机数打乱数组1000次
for(int i=0;i<1000;i++){
int index1 = (int)(Math.random()*101);
int index2 = (int)(Math.random()*101);
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
System.out.println("打乱以后的数组:");
for(int i=0;i<100;i++){
System.out.print(array[i]+"\t");
}
System.out.println();
//解决方案1:用循环实现-----效率太低
huhailong:for(int i=0;i<array.length;i++){
for(int j=i+1;j<array.length;j++){
if(array[i]==array[j]){
System.out.println("重复的元素是:"+array[i]);
break huhailong;
}
}
} //huhailong:为循环标号,以便跳出循环
//解决方案2:用一个巧合的做法
//思路:把整个数组的所有元素的值累加起来,然后用和减去0·99的和
int sum = 0;
for(int i=0;i<array.length;i++){
sum+=array[i];
}
//使用sum-和
for(int i=0;i<100;i++){
sum-=i;
}
System.out.println("重复的元素是:"+sum); //弊端:数据多的话会有数据溢出
//解决方案3:用异或
//思路:x^0^1^2^3...^99^0^1^2^3..^99 = x
for(int i=1;i<array.length;i++){
array[0] = array[0]^array[i];
}
for(int i=0;i<100;i++){
array[0] = array[0]^i;
}
System.out.println("重复的元素为:"+array[0]);
}
}
题目2:现在有0·99,共计100个整数,各不相同,将所有的数放入一个数组,随机排布。数组的长度为100,将其中任意一个数替换成0·99的另一个数(唯一重复的数字)
目标:将这个重复的数字找出来
这个问题和上面的类似,不同之处是它是在0~99之间挑一个出来进行改变,这样我们就不可以用上面方法中的方法2和方法3,因为这俩种方法都是利用元素个数的不同去实现的算法,方法1是可以实现的,这里就不说方法一了,在这里我介绍一种巧妙的算法,利用数组去查找。
思路:我们知道,新创建好的数组里面默认的每一个元素都是0,我们可以用我们要查找的数组中的元素当作我们新创建元素的下标,当我们新创建的数组中对应的有元素我们就给它加一,例如我们需要查找的数组的元素为:0 2 1 3 4 3 5,这7个元素,我们在创建一个长度为7的数组,它的每一项默认的为:0 0 0 0 0 0 0,我们将我们要查找的数组的元素当作新数组的下标,比如下标为0的对应有元素则加一,具体实现看下面代码:
/*
题目:现在有0·99,共计100个整数,各不相同,将所有的数放入一个数组,随机排布。
数组的长度为100,将其中任意一个数替换成0·99的另一个数(唯一重复的数字)
问题:将这个重复的数字找出来
分析:
1.构造数组
2.给数组添加元素
3.将其中任意一个数替换成0到99的另一个数
4.找出重复的元素
*/
public class Demo03{
public static void main(String[]args){
//构造数组
int[]array = new int[100];
for(int i=0;i<array.length;i++){
array[i] = i;
}
System.out.println();
//打乱数组1000次
for(int i=0;i<1000;i++){
int index1 = (int)(Math.random()*100);
int index2 = (int)(Math.random()*100);
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
//遍历数组
for(int i=0;i<array.length;i++){
System.out.print(array[i]+"\t");
}
System.out.println();
//将其中任意一个数替换成0到99的另一个数
int n1 = (int)(Math.random()*100);
int n2 = (int)(Math.random()*100);
//为了不让n1==n2
while(n1==n2){
n1 = (int)(Math.random()*100);
}
System.out.println("把"+n1+"位置的值换为了"+n2+"位置的值");
array[n1] = array[n2];
for(int i=0;i<array.length;i++){
System.out.print(array[i]+"\t");
}
System.out.println();
//找出元素
//解决方案1:用循环实现-----效率太低
huhailong:for(int i=0;i<array.length;i++){
for(int j=i+1;j<array.length;j++){
if(array[i]==array[j]){
System.out.println("重复的元素是:"+array[i]);
break huhailong;
}
}
} //huhailong:为循环标号,以便跳出循环
//用数组优化
/*
举例:0 1 2 3 4 5 6
打乱:1 4 2 6 5 3 0
进行数据的交换,把2用5替换
交换:1 6 2 6 5 3 0
定义一个新的数组,int[]array = new int[7];
默认元素:0 0 0 0 0 0 0
方法:把原始数组的元素作为新数组的下标,如果下标存在,就把新数组该下标对应
的元素值+1
元素:1 1 1 1 0 1 2
*/
System.out.println("-----------------------------------------------");
int[]newArray = new int[100];
for(int i=0;i<array.length;i++){
newArray[array[i]]++;
if(newArray[array[i]]==2){
System.out.println("重复的元素是:"+array[i]);
break;
}
}