题目如下:
Given an array of integers, every element appears three times except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
我们讨论一下,两次的和n次的
出现两次的:
思路一:根据异或运算特点:两个相同的数进行异或,结果为0,从头到尾异或下去,比如5,5,4,3,3,其二进制的
表示为101,101,100,11,11,这样异或的结果为:0,100,111,100,最后得到的结果为100
代码实现:
public static int singleNumber(int[] A) { int num = 0; for(int i=0;i<A.length;i++){ num^=A[i]; } return num; }
思路二:去遍历数组,对于中间的数字考虑是否前后有相同的,对于第一数字单独处理
代码实现:
import java.util.*; public class Solution { public int singleNumber(int[] A) { int i=0; Arrays.sort(A); for(i=0;i<A.length-1;i++){ if(i==0){ if(A[i]==A[i+1]){continue;} }else{ if(A[i]==A[i+1]||A[i]==A[i-1]){ continue; } } break; } return A[i]; } }出现三次或者三次以上去找那个单独的值的时候该怎么办呢?好像不能用异或了,但是考虑到输入是int型数组,所以可以用32位来表达输入数组的元素。
假设输入中没有single number,那么输入中的每个数字都重复出现了数字,也就是说,对这32位中的每一位i而言,所有的输入加起来之后,第i位一定是3的倍数。
现在增加了single number,那么对这32位中的每一位做相同的处理,也就是说,逐位把所有的输入加起来,并且看看第i位的和除以3的余数,这个余数就是single numer在第i位的取值。这样就得到了single number在第i位的取值。这等价于一个模拟的二进制,接着只需要把这个模拟的二进制转化为十进制输出即可。
另外,这个做法可以扩展,如果有一堆输入,其中1个数字出现了1次,剩下的数字出现了K次,这样的问题全部可以使用这样的办法来做。
完整代码
public class SingleNum { public static void main(String[] args) { SingleNum s=new SingleNum(); int[] arr= {2,2,2,5,2,3,4,5,4,5,4,5,4}; System.out.println(s.singleNumber(arr,4)); } public static int singleNumber(int A[],int k) { int n=A.length; int[] count=new int[32]; int result=0; for(int i=0;i<32;i++){ for(int j=0;j<n;j++){ count[i]+=((A[j]>>i)&1); //首先把输入数字的第i位加起来,这里和1去与,取到的就是一位 count[i]=count[i]%k; //然后求它们除以k的余数。 } result|=(count[i]<<i);//把二进制表示的结果转化为十进制表示的结果 } return result; } }