LeetCode :645.错误的集合

题目链接:645.错误的集合
在这里插入图片描述

数学解法

这个解法主要用到set集合性质,存储的元素不重复,与1~n集合相减,从而找到缺失元素,
对于重复元素 = 原数组 - set集合(set集合中少一个重复元素)

class Solution {
    public int[] findErrorNums(int[] nums) {
        Set set=new HashSet();
        int sums=0;
        for (int i = 0; i < nums.length; i++) {
            set.add(nums[i]);
            sums+=nums[i];
        }
        int sum_set=0,sum_num=0;
        for (int i = 1; i <= nums.length; i++) {
            sum_num+=i;
        }
        Object[] arr_set=set.toArray();
        for (int i = 0; i < set.size(); i++) {
            sum_set+=(int)arr_set[i];
        }
        int[] a=new int[2];
        a[0]=sums-sum_set;
        a[1]=sum_num-sum_set;
        return a;
    }
}

异或解法

dup:重复元素;mis:缺失元素;
异或1~n和nums每一项,得到dup^mis,相当于mis异或一次,dup异或三次,其余元素异或两次为0,0 ^ a=a;所以得到num = dup^mis
下面要对num进行拆分:
首先我们分析num的值,为dup和mis的不同位构成,通过 num^(-num) = lowbit,提取不同位里第一次出现不同的位置,将最靠右的1作为鉴别点,由此将nums中的元素分为两组num1,num2(dup和mis肯定在不同组中)
用(nums[i] & lowbit)== 0,作为条件,对两组元素都异或
对num1,num2再次for循环异或,范围1~n,条件不变,此时所得num1,num2,其中一个是dup,一个是mis,但不知道谁是谁
为什么两遍分组异或就能得到,分析num1数组,异或可以理解为1^ 2^ 3^ 4 ^ 5^……,它其实变相保存了这一组数据,第二遍异或完整的序列,那么之前的元素遇到相同的元素异或就为0,即舍去了,最终会剩下一个元素这个元素只能是重复或缺失的(即:0 ^ dup=num1或num2 ),对另一组num2也是这个道理,
最后判断num1 num2,分别是dup还是mis,dup在nums中

int* findErrorNums(int* nums, int numsSize, int* returnSize) {
    int dup_mis = 0;
    for (int i = 1; i <= numsSize; i++) {
        dup_mis ^= i;
        dup_mis ^= nums[i - 1];
    }//两遍异或得到  重复^缺失
    //分离这个异或结果dup_mis
    int lowbit = dup_mis & (-dup_mis);//提取不同位里第一次出现不同的位置
    int num1 = 0, num2 = 0;
    for (int i = 0; i < numsSize; i++) {
        if ((nums[i] & lowbit) == 0) {
            num1 ^= nums[i];
        } else {
            num2 ^= nums[i];
        }
    }
    for (int i = 1; i <= numsSize; i++) {
        if ((i & lowbit) == 0) {
            num1 ^= i;
        } else {
            num2 ^= i;
        }
    }
    int* a=(int*)malloc(sizeof(int)*2);
    *returnSize = 2;
    for (int i = 0; i < numsSize; i++) {
        if (nums[i] == num1) {
            a[0] = num1, a[1] = num2;
            return a;
        }
    }
    a[0] = num2, a[1] = num1;
    return a;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值