数组中只出现一次的数

一个只出现一次的数,其他出现两次
  • 全部的数异或,最后的数就是要找的数
class Solution {
    public int singleNumber(int[] nums) {
        int res = nums[0];
        for(int i=1;i<nums.length; i++){
            res ^= nums[i];
        }

        return res;
    }
}
两个只出现一次的数,其他出现两次
  • 假设两个出现一次的数为p,q,如果能找到p和q中间的数,将数组分为两半,左边异或得到p,右边异或得到q。

  • 怎么找到 p 和 q 中间的数字 r 呢?二分。在这里插入图片描述

  • 但是,你以为这完了吗?异或和为 00 其实并不代表 要找的元素不在这里面,因为有可能 00 只出现了 11 次! 所以这种思路需要特判一下某个数为 00 的情况。

什么?这题还可以用二分查找?

class Solution {
    public int[] singleNumbers(int[] nums) {
        int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
        int zero = 0;
        int sum = 0;
        for(int i=0; i<nums.length; i++) {
        	min = Math.min(min, nums[i]);
        	max = Math.max(max, nums[i]);
        	
        	if(nums[i] == 0)
        		zero += 1;
        	sum ^= nums[i];
        }
        
        if(zero == 1)
        	return new int[] {sum, 0};
        
        int left = min, right = max;
        while(left <= right) {
        	//int mid = (left < 0 && right > 0)? (left + right) >> 1: left + (right - left) / 2;
        	int mid = (left + right) / 2;
        	int leftSum = 0, rightSum = 0;
        	for(int n : nums) {
        		if(n < mid)
        			leftSum ^= n;
        		else
        			rightSum ^= n;
        	}
        	
        	if(leftSum != 0 && rightSum != 0)
        		return new int[] {leftSum, rightSum};
        	if(leftSum == 0)
        		left = mid +1;
        	if(rightSum == 0)
        		right = mid - 1;
        }
        
        return null;
    }
}
只出现一次的数,其他数字出现三次

在这里插入图片描述

在这里插入图片描述

class Solution {
    public int singleNumber(int[] nums) {
        //二进制中各个位上1的个数
        int[] numOne = new int[32];
        for(int n:nums){
            for(int i=0;i<32;i++){
                numOne[i] += n&1;
                n >>= 1;
            }
        }

        //%3
        int res = 0;
        for(int i=0;i<32;i++){
            res <<= 1;
            res |= numOne[31 - i] % 3;
        }
        return res;
    }
}

【参考文档】数组中数字出现的次数 II(位运算 + 有限状态自动机,清晰图解)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值