[剑指Offer]56-数组中数字出现的次数(位运算)
题目一 数组中只出现一次的数字
题目
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字
题解
- 异或。
- 先考虑:数组中只有一个数字只出现了一次,其他数字都出现了两次,怎么找出这个数字?全部异或,结果即为所求数字。
- 那么,原问题可以将原数组分成两个集合,两个集合都满足上面的题目,则可求出两个出现一次的数字,那么分组方法?分组:将所有数都做异或,一定至少有一位是1,因为存在两个不相同数字。先找出这一位,然后按这一位是0/1分为两组,两组自然就满足了上面的要求,可求的结果。
- 综上,步骤一:分组,步骤二:全部异或求得数字。
相关
- 异或运算可初始化为0,因为0与任何数异或都是它本身。
- 找到最后一个1:
num&(~num+1)
代码
public class Main {
public static void main(String[] args) {
int[] arr= {2,4,3,6,3,2,5,5};
int[] num1=new int[1];
int[] num2=new int[1];
FindNumsAppearOnce(arr,num1,num2);
System.out.println(num1[0]);
System.out.println(num2[0]);
}
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public static void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
if(array==null||array.length<2) {
return;
}
//所有数异或
int xorResult=0;
for(int i=0;i<array.length;++i) {
xorResult^=array[i];
}
//找到(最后一个)为1的位
int bitPos=findFirstOnePos(xorResult);
num1[0]=0;
num2[0]=0;
for(int i=0;i<array.length;++i) {
if((array[i]&bitPos)==0) {//bitPos位为0的分为一组
num1[0]^=array[i];//该组内所有数异或,结果即为第一个出现一次的数
}
else {//bitPos为1的分为一组
num2[0]^=array[i];//该组内所有数异或,结果即为第二个出现一次的数
}
}
}
//获得二进制最后一个1的位置
private static int findFirstOnePos(int num) {
return num&(~num+1);
}
}
题目二 数组中唯一只出现一次的数字
题目
一个数组中,一个数字只出现一次,其他数字都出现三次,找出只出现一次的数字
题解
-
用一个32位数组,记录每个数对应位相加的和,每位%3的结果得到的数字就是所求数字。
时间复杂度O(n),空间复杂度O(1). -
其他解法:排序,再找,时间复杂度O(nlogn);或者哈希表,空间复杂度O(n).
相关
涉及到了知道哪些位是1,通过位移和与运算得到最终的数。
代码
public class Main {
public static void main(String[] args) {
int[] arr= {1,2,3,3,2,1,4,1,2,3};
System.out.println(occurOnce(arr));
}
public static int occurOnce(int[] nums) {
int[] bitSum=new int[32];
for(int i=0;i<nums.length;++i) {
int bitMask=1;
for(int j=0;j<31;++j) {
if((nums[i]&bitMask)!=0) {
++bitSum[j];
}
bitMask<<=1;
}
}
int ans=0;
for(int i=31;i>=0;--i) {//高位移的多,按从高到低位遍历
ans<<=1;
ans+=bitSum[i]%3;
}
return ans;
}
}
posted on 2019-07-10 12:26 coding_gaga 阅读(215) 评论(0) 编辑 收藏 举报