leetcode——“数组中重复的数据” 详解

本文介绍了如何使用一个简单的for循环和swap函数,将数组中的重复数字移动到正确位置,然后通过一次遍历来找出并返回所有重复项。涉及的步骤包括元素交换、位置调整和空间复杂度分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接如下:

442. 数组中重复的数据

题目:

方法一:将元素交换到对应位置

void swap(int* pa,int* pb)
{
    int tmp=*pa;
    *pa=*pb;
    *pb=tmp;
}
int* findDuplicates(int* nums, int numsSize, int* returnSize){
    int i=0;
    int j=0;
    for(i=0;i< numsSize;i++)    //走 numsSize 趟
    {
        while(nums[i]!=nums[nums[i]-1])   
        {
            swap(&nums[i],&nums[nums[i]-1]);
        }
    }
    int* ans=(int*)malloc(sizeof(int)* numsSize);
    for(i=0;i< numsSize;i++)
    {
        if(nums[i]!=i+1)
        {
            ans[j++]=nums[i];
        }
    }
    * returnSize=j;
    return ans;
}

 通过第一个for循环将每一个数放在对应的位置。由于数组的下标范围是 [0, n-1],我们需要将数 i 放在数组中下标为 i−1 的位置:

●如果i恰好出现了一次,那么将i放在数组中下标为i- 1的位置即可;
●如果i出现了两次,只要其中的一个 i 放在数组下标中为i- 1的位置, 另一个i放置在任意的位置,假设下标是 j ,也就是说数 j+ 1没有在数组中出现过。
举个例子:4,3,2,7,8,2,3,1  经历第一次for循环后就会变成:     1 2 3 4 3 2 7 8        

所以这样放置完一遍后, 那么我们只需要对数组进行一次遍历。当遍历到位置 i 时,如果nums[i] ≠ i+1,说明nums[i]出现了两次(另一次出现在num[ num[i]- 1 ] ),我们就可以将num[i]放入答案。

自己malloc一个需要返回的数组ans,我们先开 numsSize 个整形大小,作为返回值的数组不算在额外开辟的空间中,所以空间复杂度依旧符合O(1),比如上面已经放置后的 1 2 3 4 3 2 7 8   ,nums[4] != 5,说明nums[4] 这个值出现了2次,直接把nums[4] 赋值给 数组ans,并用 j 记录ans下标大小,赋值完后 j 就是数组ans的大小,* returnSize=j;   return ans; 即可。

单独讲一下第一个for:

   for(i=0;i< numsSize;i++)   
    {
        while(nums[i]!=nums[nums[i]-1])   
        {
            swap(&nums[i],&nums[nums[i]-1]);
        }
    }

 走 numsSize 趟,每趟把nums[i]这个数放到他对应的下标的位置nums[nums[i]-1],nums[i]和nums[nums[i]-1]相等停下的条件有2个:如果nums[i]恰好就是在他应该在的下标的位置就不用进行了 或者 nums[i]和对应下标位置nums[nums[i]-1]是重复数字也停下,经过 numsSize 趟,就会把所有nums[i] 放进对应位置,重复的数字有一个在对应位置,另一个在缺失数字的位置。

动态图过程)此动图只做到了i=3,仅助于大家理解

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值