文章目录
前言一、题目二、题解1.奇巧淫技2.其他解法使用辅助空间不使用辅助空间 相关前言
位运算 异或(^)蛮有意思的,分享一下。
一、题目
1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。
每个数组元素只能访问一次,设计一个算法,将它找出来。
不用辅助存储空间,能否设计一个算法实现?
提示:异或( ^ )可以去除两个重复的值。
二、题解
1.奇巧淫技
利用异或( ^ ) 可以去重这一特点。a异或a等于0,a异或0等于a(101异或101等于0)例如,A ^ A ^ B ^ C ^ C等于B,因为A^A等于0,消除重复了。
解释:
先将 1 -1000的每一个数都 异或( ^ ) 一次。如果此时再将1-1000异或一次,那么值则为0了。
因为在数值中,有1001个数,中间有两个数是相同的。因为第一个for循环 异或^ 了1-1000,此时再次for循环遍历数组中所有数,同时 异或^ 所有数,那么重复的那个数字将会被保留下来,所以那个数字即为重复的数。(两个for循环中,重复的数字一共出现了3次,其他数只出现了两次)
使用异或^。时间复杂度为O(n)。
public static int solution(int[] arr) {int x = 0;// 先将1-1000异或一次,1^2^3^...^1000。for (int i = 1; i <= 1000; i++) {x = x ^ i;}// 再将1-1000异或一次,但是这里包含了一个重复的数(这个重复的数总共会被异或^三次,从而保留下来)。for (int i = 0; i < arr.length; i++) {x = x ^ arr[i];}return x;}
测试数据main方法
public static void main(String[] args) {// 随便生成的测试数据(数据可能是乱序的,我这里只是为了方便)int[] arr = new int[1001]; for (int i = 0; i < 1000; i++) {arr[i] = i + 1;}arr[1000] = (int)(Math.random() * (1000+1-1))+1; // 随机生成[1-1000]内的数// 测试System.out.print(solution(arr));}
2.其他解法
使用辅助空间
新建了一个HashSet。使用 Set 不能添加重复的特点,如果找到重复的了就返回那个值。
public static int solution2(int[] arr) {HashSet<Integer> set = new HashSet<>();for (int i = 0; i < arr.length; i++) {boolean add = set.add(arr[i]);if (!add) {return arr[i];}}throw new IllegalArgumentException("数组中没有两个相同的数!");}
新建了一个数组。因为值的范围在 1-1000,所以用值来作为新数组的下标,将值+1。
第二个for循环遍历,找出被值为2的下标,即重复出现的数。
public static int solution3(int[] arr) {int[] newArr = new int[1001];for (int i = 0; i < arr.length; i++) {int value = arr[i];newArr[value]++;}for (int i = 0; i < newArr.length; i++) {if (newArr[i] == 2) {return i;}}throw new IllegalArgumentException("数组中没有两个相同的数!");}
不使用辅助空间
暴力破解。时间复杂度有点高,为O(n2)
每找一个数时,判断这个数在数组中是否存在,存在则直接返回。
public static int solution4(int[] arr) {for (int i = 0; i < arr.length; i++) {for (int j = i+1; j < arr.length; j++) {if (arr[i] == arr[j]) {return arr[i];}}}throw new IllegalArgumentException("数组中没有两个相同的数!");}
相关
更多奇淫巧技的题解请点击:【奇淫巧技】题解集