剑指offer面试题56:数组中数字出现的次数(Java 实现)

题目一:在一个数组中除了一个数字只出现一次之外,其他数字都出现了2次,请找出那个只出现了一次的数字。
要求:线性时间复杂度O(N),空间复杂度为O(1)。

思路:用异或运算来解决问题,由于两个相同的数字的异或结果是0,我们可以把数组中的所有数字进行异或操作,结果就是唯一出现的那个数字。

public int FindANumAppearOnce(int[] array){
		int ans = 0;
		
		for(int i=0; i<array.length; i++){
			ans = ans^array[i];
		}
		return ans;
	}

题目二:在一个数组中除了2个数字只出现一次之外,其他数字都出现了2次,请找出两个只出现了一次的数字。 
要求:线性时间复杂度O(N),空间复杂度为O(1)。

思路:从头到尾异或数组中的每个数字,可以得到只出现1次的两个数字的异或结果。从异或结果中,找到右边开始第一个为1的位数,记为n。我们将数组中所有的数字,按照第n位是否为1,分为两个数组。每个子数组中都包含一个只出现一次的数字,其它数字都是两两出现在各个子数组中。那么结合题目一,我们已经得出了答案。

 

public int[] FindTwoNumsAppearOnce(int[] array) throws Exception{
        if(array == null || array.length == 0)
			throw new Exception("无效输入");

		int ans = 0;
		
		//首先计算出数组中所有数组异或的结果
		for(int i=0; i < array.length; i++){
			ans = ans ^ array[i];
		}
		//得到这个异或结果的最右边第一个为1的位数
		int indexOf1 = FindFirstBitIs1(ans);
		
		int num1 = 0;
		int num2 = 0;
		
		//将整个数组按从右边起第indexOf1为是不是1分为两组
		for(int i=0; i < array.length; i++){
			if(IsBit1(array[i], indexOf1) == true){
				num1 = num1 ^ array[i];
			}
			else{
				num2 = num2 ^ array[i];
			}
		}
		int[] result = {num1, num2};
		return result;
	}
	
	//判断一个数从右边算起第index位是不是1
	private boolean IsBit1(int num, int index) {
		num = num >> index;
		return (num&1) == 1? true : false;
	}


	private int FindFirstBitIs1(int num) {
		int index = 0;
		while((num&1) == 0){
			num = num >> 1;
			index++;
		}
		return index;
	}

题目三:在一个数组中除了一个数字只出现一次之外,其他数字都出现了3次,请找出那个只出现了一次的数字。 
要求:线性时间复杂度O(N),空间复杂度为O(1) 。

思路:如果一个数字出现三次,那么他的二进制表示的每一位(0或者1)也出现3次。如果把所有出现3次的数字的二进制表示的每一位都分别相加起来,那么每一位的和都能被3整除。

public int FindANumAppearOnce1(int[] array) throws Exception{
		if(array == null || array.length ==0)
			throw new Exception("无效输入");
		
		//定义一个数组来存储数组中每一个数字的32位数的和
		int[] bitSum = new int[32];
		
		//遍历数组
		for(int i=0; i < array.length; i++){
			int bitMask = 1;
			
			//遍历从后往前存储数字的每一位数
			for(int j=31; j >= 0; j--){
				int bit = array[i] & bitMask;
				
				if(bit != 0){
					bitSum[j] = bitSum[j] + bit;
				}
				
				bitMask = bitMask << 1;
			}
		}
		
		int result = 0;
		for(int i=0; i<32; i++){
			result = result + bitSum[i] % 3;
		}
		return result;
	}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值