(剑指offer)JZ3 数组中重复的数字[cpp实现]


1. 题目描述

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。
也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
例如,如果输入长度为7的数组[2,3,1,0,2,5,3],那么对应的输出是2或者3。存在不合法的输入的话输出-1

数据范围:0≤n≤10000
进阶:时间复杂度O(n),空间复杂度O(n)


2. 运行示例

输入:[2,3,1,0,2,5,3]
返回值:2
说明:2或3都是对的


3. 解决方法


3.1 方法一

     思路:最容易想到的一种方法,对数组中的数据进行排序,然后一次遍历,比较找出第一个重复的数字进行返回。


代码实现:

int duplicate(vector<int>& numbers) {
    // write code here
    sort(numbers.begin(),numbers.end()); // 从小到大排序
    for(int i = 1;i<numbers.size();++i) // 这里从1开始
        if(numbers[i-1]==numbers[i]) // 判断当前数字是否和前面一个相同 即出现重复
            return numbers[i];
    return -1;
}

时间复杂度:O(nlogn)


3.2 方法二

     思路:使用set集合,如果set集合中没有当前数字,那么将其加入到set集合中;
如果出现了当前数字,那么当前数字即出现重复,返回当前数字。

这里简单说明一下set集合的使用:set集合中将数据从大到小排列,且不含重复元素。


代码实现:

int duplicate(vector<int>& numbers) {
    // write code here
    set<int> s;
    for(int i=0;i<numbers.size();++i){ // 遍历numbers
        if(s.find(numbers[i]) == s.end()) // 如果find查询当前元素返回的是end迭代器 那么即集合中不含当前元素
           s.insert(numbers[i]); // 将当前元素插入到set集合中
        else
           return numbers[i]; // 否则返回当前元素
    }
    return -1;
}

时间复杂度:O(n)


3.3 方法三

     思路:注意题目中的一句话:“在一个长度为n的数组里的所有数字都在0到n-1的范围内。”,那么现在可以将元素和对应容器的下标对应起来,比如:

数组下标:0 1 2 3 4 5 6
对应元素:3 2 1 2 4 6 3

     从头开始遍历数据,如果当前元素值和对应其下标值不相同,并且当前元素值和用当前元素作为下标的那个元素值不相同的话,那么将当前元素和与用当前元素做下标的元素进行交换,从而得到了一个数组下标和元素对应的数据;如果相同,那么继续查看下一元素,因此,上面举例可以进行如下变换:

数组下标:0 1 2 3 4 5 6
对应元素:2 2 1 3 4 6 3

数组下标:0 1 2 3 4 5 6
对应元素:1 2 2 3 4 6 3

数组下标:0 1 2 3 4 5 6
对应元素:2 1 2 3 4 6 3

     此时如果再进行一次变换,可以发现[0]中元素2和[2]中元素2出现了重复,那么则返回该重复元素。


代码实现:

    int duplicate(vector<int>& numbers) {
        // write code here
        for(int i = 0;i<numbers.size();++i){
            while(numbers[i]!=i){
                if(numbers[i] == numbers[numbers[i]])
                    return numbers[i];
                else
                    swap(numbers[i],numbers[numbers[i]]);
            }
        }
        return -1;
    }

时间复杂度:O(n)


自己感觉第三中方法叙述解释的不是太好,欢迎批评指正。

——————END-2022-05-01——————

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苡荏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值