【算法笔记:数组中重复的数字】

问题描述

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

数据范围

0 <= n <= 10000

示例

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

思路

首先数组里面的所有数字都在0到n - 1的范围内,所以需要遍历完整个数组寻找是否有不合法的数字。
题目要求只要找到任意一个重复的数字即可,所以只要找到一个重复的数字即可返回输出。
故时间复杂度最少也是O(n)。

思路一 暴力破解

暴力破解:第一层选择数组中的一个数字,与剩下的n-1个数字进行比较,若发现相同的两个数字,就返回正确的结果。
复杂度:
时间复杂度:O(n^2)
空间复杂度:O(1)
代码如下:

class Solution {
public:
    int duplicateInArray(vector<int>& nums) {
        int n = nums.size();
        for (auto num : nums)
            if(num < 0 || num > n) return -1;
        //核心代码
        for (int i = 0; i < n - 1; i ++ )
            for (int j = i + 1; j < n; j ++ )
                if(nums[i] == nums[j]) return nums[i];

        return -1;
    }
};

思路二 排序后遍历

排序后遍历:

  1. 首先对数组进行排序推荐使用sort()可达到O(nlogn)的复杂度
  2. 之后遍历数组即可,若发现有两个连续的元素即返回。

复杂度:
时间复杂度:O(nlogn)
空间复杂度:O(1)
代码如下:

class Solution {
public:
    int duplicateInArray(vector<int>& nums) {
        int n = nums.size();
        for (auto num : nums)
            if(num < 0 || num > n) return -1;
        //核心代码
        sort(nums.begin(), nums.end());
        for (int i = 0; i < n - 1; i ++ )
            if (nums[i] == nums[i + 1]) return nums[i];
        return -1;
    }
};

思路三 hash散列

Hash散列:

  1. 遍历一遍nums数组,并且查询hash表
  2. 如果说查询表中已有那么就返回该数,如果没有那么添加进去即可。

复杂度分析:
时间复杂度:O(n),只遍历了一遍
空间复杂度:O(n),最坏情况将数组中的所有数存入hash表中
代码如下:

class Solution {
public:
    int duplicateInArray(vector<int>& nums) {
        int n = nums.size();
        for (auto num : nums)
            if(num < 0 || num > n) return -1;
        //核心代码
        set<int> res;
        for (int i = 0; i < n; i ++ )
            if(res.count(nums[i]) > 0) return nums[i];
            else res.insert(nums[i]);
        return -1;
    }
};

虽然使用hash表的时间的复杂度可以达到O(n),但是空间复杂度也达到了O(n),所以需要一种新的方法来找重复的数字。

思路四 数据重排

数据重排:

  1. 扫描数组nums中的每一个元素,当扫描到第i个元素的时候,比较i与nums[i]是否相等,如果相等说明i已经归位了
  2. 如果不相等,那么比较nums[i]与nums[nums[i]]是否相等,如果不相等那么交换两个元素的位置,让num[i]归位.
  3. 如果相等那么就意味着有重复的元素,即返回。

复杂度分析:
时间复杂度:O(2n),扫描一遍,交换一遍
空间复杂度:O(1)
图解:
感谢牛客@鸠摩罗什

代码如下:

class Solution {
public:
    int duplicateInArray(vector<int>& nums) {
        int n = nums.size();
        for (auto num : nums)
            if(num < 0 || num > n) return -1;
        //核心代码
        for (int i = 0; i < n; i ++ ) {
            if (i != nums[i] && nums[i] != nums[nums[i]]) 
                swap(nums[i], nums[nums[i]]);
            if (i != nums[i] && nums[i] == nums[nums[i]])
                return nums[i];
        }
        return -1;
    }
};

参考:《剑指Offer》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值