三种方法详解:剑指Offer 03. 数组中重复的数字

探讨了在长度为n的数组中查找重复数字的三种方法:排序、集合法及就地交换,适用于数字范围在0~n-1的情况。

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

LeetCode:剑指Offer 03. 数组中重复的数字

原题LeetCode链接:剑指Offer 03. 数组中重复的数字

题目:找出数组中重复的数字

​ 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例1:

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2或3

限制:2 ≤ n ≤ 100000

方法一:排序

​ 思路:数组元素是数字,对其进行排序,若有重复则在排序后数组的相邻位置,遍历数组即可找到。排序时间复杂度O(nlogn),空间复杂度O(1)。C++代码如下:

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int length = nums.size();
        for(int i = 0; i < length-1; i++){
            if(nums[i] == nums[i+1]){
                return nums[i];
            }
        }
        return -1;
    }
};

tips: sort()用法:

头文件:#include<algorithm>
void sort (RandomAccessIterator first, RandomAccessIterator last);
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

first:待排序数组起始位置;

last:待排序数组末尾位置,要排序的最后一个元素的后一个元素位置,[first,last);

comp:排序的方法,可以是升序也可以是降序,不写则默认升序。

方法二:集合法、unordered_set

思路:首先构建一个空集合,然后遍历数组,如果元素不在集合中则将其插入集合中;若元素在集合中,则说明有重复。

tips :set内部使用红黑树实现,具有自动排序的功能,因此内部元素在任何时候都是有序的;unordered_set基于哈希表,数据插入和查找时间复杂度低,代价是消耗较多内存,不能自动排序。本题只需要插入与查找,因此选用unordered_set 时间上的差别可自行尝试使用两种结构进行提交。空间复杂度O(n),时间复杂度为O(n)。C++代码如下:

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        unordered_set<int> s;
        int length = nums.size();
        for(int i = 0; i < length; i++){
            if(s.find(nums[i]) == s.end()){
                s.insert(nums[i]);
            }
            else{
                return nums[i];
            }
        }
        return -1;
    }
};

方法三:就地交换

思路:因为数组中的数字都是在0~n-1范围内的,如果没有重复的元素那么数据值和下标应该是相等的。而如果有重复的值的话,有些位置放的就不是对应的值,那么我们可以尝试将它放回对应的位置。

1)如果对应的位置有一个符合的元素,就说明该数字重复了;

2)如果对应的位置也不是符合的元素,那么就将两者交换,将上一个元素和正确位置配对,继续寻找新的元素的位置。

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int length = nums.size();
        for(int i = 0; i < length; i++){
            if(i == nums[i]){//如果元素和位置对应,则继续
                continue;
            }
            else{//否则
                while(i != nums[i]){//循环,直到元素与位置对应
                    if(nums[nums[i]] == nums[i]){//此元素对应的位置上已经有一个符合的了
                        return nums[i];//说明已经重复,返回元素即可
                    }
                    else{//元素对应位置上也是不符合的元素,那么就和此元素交换使它符合,然后继续寻找新位置
                        int temp = nums[nums[i]];
                        nums[nums[i]] = nums[i];
                        nums[i] = temp;
                    }
                }
            }
        }
        return -1;
    }
};

如果有错误之处,还望指出!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值