剑指--数组中数字出现的次数

剑指–数组中数字出现的次数

1,题目:
在这里插入图片描述
2,思路:

方法一:异或运算

由于数组中存在着两个数字不重复的情况,我们将所有的数字异或操作起来,最终得到的结果是这两个数字的异或结果:(相同的两个数字相互异或,值为0,不同的异或,值为1)) 最后结果一定不为0,因为有两个数字不重复。

(1)首先,得到异或结果,即为不相同两个数的异或结果sum(如用4 4 6 1来举例的话,这时sum为0111)

(2)再用&运算,所以我们可以根据数组元素的二进制低位第一位是否为1,将数组分为2类:

  • 示例数组可以分为 低位第一位为0:[4,4,6] 低位第一位为1:[1]

  • 此时再将两个数组两两异或就可以得到最终结果。

  • 需要注意的是,分组的结果必然是相同的数在相同的组,且还有一个结果数

  • 因此每组的数再与res=0一路异或下去,最终会得到那个结果数A或B

  • 且由于异或运算具有自反性,因此只需得到其中一个数即可

方法二:双指针:

  • 首先,对原数组进行排序 其次,新建结果数组res[],并用i指针指向这个结果数组

  • 再次,用left,right指针指向原数组的起始和结束位置

  • 再次,判断nums[left]和nums[left++],和nums[right]和nums[right–]是否相等来跳过重复数组

  • 最后,如果相等则跳过,指针移动;若不相等就证明此时这个值就出现了一次,这个值就是想要的结果,把其赋予给结果数组res中即可。

3,代码:
方法一:异或运算

class Solution {
    public int[] singleNumbers(int[] nums) {
      int sum=0;
        //将数组所有元素进行异或,最后的结果一定是那两个单一数字的异或结果。看上图示例
        //用示例[4,4,6,1]最后的抑或结果就是 6和1异或的结果 7
        for (int i = 0; i <nums.length ; i++) {
            sum^=nums[i];//得到异或结果,即为不相同两个数的异或结果sum
              //如用4 4 6 1来举例的话,这时sum为0111
        }
        int first = 1;
        //通过与运算找到result第一个不为0的首位,7=>0111,也就是第一位
        while((sum&first)==0){
            first=first<<1;//这时候指针指到了0后面的1,也就是第一个不为0的首位
        }

        //first为1,所以我们可以根据数组元素的二进制低位第一位是否为1,将数组分为2类,
        // 示例数组可以分为     低位第一位为0:[4,4,6]     低位第一位为1:[1]
        //此时再将两个数组两两异或就可以得到最终结果。
           //需要注意的是,分组的结果必然是相同的数在相同的组,且还有一个结果数
            //因此每组的数再与res=0一路异或下去,最终会得到那个结果数A或B
            //且由于异或运算具有自反性,因此只需得到其中一个数即可
        int result[]=new int[2];
        for(int i=0;i<nums.length;i++){
            //将数组分类。
            if((nums[i]&first)==0){//表示低位第一位为0的
                result[0]^=nums[i];
            }
            else{//表示低位第一位为1的
                result[1]^=nums[i];
            }
        }
        return result;
    }
}

方法二:双指针:

class Solution {
    public int[] singleNumbers(int[] nums) {
        Arrays.sort(nums);
        int[] res = new int[2];
        int i = 0;
        int left = 0;
        int rigth = nums.length - 1;
        while(left <= rigth){
            if(nums[left] != nums[left + 1] && i <2){
                res[i++] = nums[left];//就表示这个值就出现了一次,所以把放入到结果数组中
                left++;
            }else{
                left += 2;//这是从左边跳过重复元素
            }
            if(nums[rigth] != nums[rigth - 1] && i<2){
                res[i++] = nums[rigth];//就表示这个值就出现了一次,所以把其放入到结果数组中
                rigth--;
            }else{
                rigth -= 2;//这是从右边跳过重复元素
            }
        }
        return res;
    

        


    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值