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
    评论
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值