* 面试题56:数组中数字出现的次数
* 题目一:数组中只出现一次的两个数字
* 一个整型数组中除两个数字之外,其他数字都出现了两次。
* 请写程序找出这两个只出现一次的庶长子。
* 要求时间复杂度O(n),空间复杂度O(1).
* 例如:输入数组{2,4,3,6,3,2,5,5},因为只有4和6这两个数字只出现了一次,
* 其他数字都出现了两次,所以输出4和6
*
* 思路:
* 异或运算: 任何一个数字异或它自己都等于0
* 所以我们可以从头到尾依次异或数组中的每一个数字,
* 那么最终的结果刚好是只出现一次的数字,因为出现两次的数字全部在异或运算中抵消了
*
* 将数组分为两个子数组,
* 在每个子数组中,包含一个只出现一次的数字,而其他数字都出现了两次
* 若是能够这样拆分数组,那么按照上面的异或运算过程就能求出出现一次的数字
*
* 每个子数组都是从头开始依次进行异或运算,因为有两个数字肯定不一样,那么异或的结果一定不为0
* 也就是说这个结果数字二进制表示中至少有一位为1
* 在结果数字中找到第一个为1的位的位置,记为第N位。现在以第N位是不是1为标准将原数组分成两个子数组
*
* 第一个数组中每个数字的第N位都是1,第二个数组中每个数字的第N位都为0
*
* 现在已经将原数组分为两个子数组,每个子数组都包含一个只出现一次的数字
* 出现两次的数字都已经抵消
package Test;
public class No56First_FindNumsAppearOnce {
/*
* 面试题56:数组中数字出现的次数
* 题目一:数组中只出现一次的两个数字
* 一个整型数组中除两个数字之外,其他数字都出现了两次。
* 请写程序找出这两个只出现一次的庶长子。
* 要求时间复杂度O(n),空间复杂度O(1).
* 例如:输入数组{2,4,3,6,3,2,5,5},因为只有4和6这两个数字只出现了一次,
* 其他数字都出现了两次,所以输出4和6
*
* 思路:
* 异或运算: 任何一个数字异或它自己都等于0
* 所以我们可以从头到尾依次异或数组中的每一个数字,
* 那么最终的结果刚好是只出现一次的数字,因为出现两次的数字全部在异或运算中抵消了
*
* 将数组分为两个子数组,
* 在每个子数组中,包含一个只出现一次的数字,而其他数字都出现了两次
* 若是能够这样拆分数组,那么按照上面的异或运算过程就能求出出现一次的数字
*
* 每个子数组都是从头开始依次进行异或运算,因为有两个数字肯定不一样,那么异或的结果一定不为0
* 也就是说这个结果数字二进制表示中至少有一位为1
* 在结果数字中找到第一个为1的位的位置,记为第N位。现在以第N位是不是1为标准将原数组分成两个子数组
*
* 第一个数组中每个数字的第N位都是1,第二个数组中每个数字的第N位都为0
*
* 现在已经将原数组分为两个子数组,每个子数组都包含一个只出现一次的数字
* 出现两次的数字都已经抵消
*
* */
public static void main(String[] args) {
// TODO Auto-generated method stub
No56First_FindNumsAppearOnce f = new No56First_FindNumsAppearOnce();
int[] array = {2,4,3,6,3,2,5,5};
int num1 = 0;
int num2 = 0;
int[] num = f.FindNumsAppearOnce(array,num1,num2);
System.out.println("数组中只出现一次的两个数字是:"+num[0]+","+num[1]);
}
public int[] FindNumsAppearOnce(int[] array,int num1,int num2) {
if(array == null || array.length == 0)
return null;
int res = 0;
//从头到尾依次异或运算 异或结果res
for(int i = 0;i < array.length;i++)
res ^= array[i];
//根据异或结果res 判断出第一位为1的位置 记为第N位
int firstIndex = findFirstIndex(res);
num1 = 0;
num2 = 0;
//根据第N位是否为1将原数组分为两个子数组
for(int i = 0;i < array.length;i++) {
//判断第N(firstIndex)位 是1还是0
//若返回true,则是1 则进入num1数组进行异或运算
//若返回false,则是0 则进入num2数组进行异或运算
if(isBit1(array[i],firstIndex))
num1 ^= array[i];
else
num2 ^= array[i];
}
int[] num = {num1,num2};
return num;
}
//判断二进制数中firstIndex位是否为1 若为1 返回true 若为0 返回false
private boolean isBit1(int item, int firstIndex) {
// TODO Auto-generated method stub
boolean check = false;
//将item右移firstIndex位,则将第firstIndex位移动到最后
item = item>> firstIndex;
//只有最后一位也为1时,才能与运算之后仍为1
if((item & 1) == 1)
check = true;
return check;
}
//二进制数 从右到左找到第一个“1” 返回N值
private int findFirstIndex(int res) {
// TODO Auto-generated method stub
int index = 0;
//因为1 和 1与结果仍为1 所以这是在找第一个为1的位置
//并且要保证位数不能超过32位(因为int类型变量占4个字符=32位)
while((1 & res) == 0 && index < 32) {
res = res >> 1;
index ++;
}
return index;
}
}
* 面试题56:数组中数字出现的次数
* 题目二;数组中唯一只出现一次的数字
* 自一个数组中除一个数字只出现一次以外,其他数字都出现了三次。
* 请找出那个只出现一次的数字
* https://www.jianshu.com/p/258785bdf416
*
* 思路:位运算思想
* 若一个数字出现了第三次,那么它的二进制标识的每一位(0或1)也出现了三次。
* 若是将所有出现三次的数字的二进制表示的每一位都分别加起来,那么每一位都能被3整除
* 那么就只有出现一次的数字不能被3整除,因而求出只出现一次的数字
package Test;
public class No56Second_FindNumberAppearOnce {
/*
* 面试题56:数组中数字出现的次数
* 题目二;数组中唯一只出现一次的数字
* 自一个数组中除一个数字只出现一次以外,其他数字都出现了三次。
* 请找出那个只出现一次的数字
* https://www.jianshu.com/p/258785bdf416
*
* 思路:位运算思想
* 若一个数字出现了第三次,那么它的二进制标识的每一位(0或1)也出现了三次。
* 若是将所有出现三次的数字的二进制表示的每一位都分别加起来,那么每一位都能被3整除
* 那么就只有出现一次的数字不能被3整除,因而求出只出现一次的数字
*
*
* */
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] array = {1,2,3,4,1,1,2,3,3,2};
No56Second_FindNumberAppearOnce f = new No56Second_FindNumberAppearOnce();
System.out.println("数组中唯一只出现一次的数字是:"+f.FindNumberAppearOnce(array));
}
private int FindNumberAppearOnce(int[] array) {
// TODO Auto-generated method stub
if(array == null && array.length < 3)
return 0;
//存储一个int(长度为32位)的每一bit的状态
int[] bitSum = new int[32];//记录每一位的和
int k = 3;
//每一位 异或运算的结果
for(int i = 0;i < array.length;i++) {//控制array数组
int indexOfBit1 = 1;
for(int j = 31;j >= 0;j--) {//控制bitSum数组
//indexOfBit1 : 1,10,100,1000,10000,100000,...
//若与运算不为0 则表示该位值为1 则令其位计数加1
if((array[i] & indexOfBit1) != 0)
bitSum[j] += 1;
//结束之后将数左移一位
indexOfBit1 <<= 1;
}
}
//将异或结果除以3 记录每一位的值
int result = 0;
for(int i = 0;i < 32;i++) {
result <<= 1;
result += bitSum[i]%k;
}
return result;
}
}