三种解法实现剑指 Offer 03. 数组中重复的数字

Posted 来老铁干了这碗代码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三种解法实现剑指 Offer 03. 数组中重复的数字相关的知识,希望对你有一定的参考价值。

立志用最少的代码做最高效的表达


题目链接——>传送门


找出数组中重复的数字。

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

示例 1:

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

限制:

2 <= n <= 100000


解法一:排序

解决这个问题一个简单办法就是先把输入的数组排序,从排序的数组中找出重复的数字是一件很容易的事情,只需从头到尾扫描即可。

时间复杂度为O(nlogn),空间复杂度O(1)

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

解法二:哈希表

构造一个长度为n的哈希表,遍历数组,每扫描到一个数字,都判断其是否在哈希表中存在,若不存在,则加入;若存在,则为重复数字。

时间复杂度为O(nlogn),空间复杂度O(n)

代码一:c++内置容器unordered_map实现(耗时较高)

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        unordered_map<int,int>um;
        int k = 0;
        for(auto i : nums) {
            um[i]++;
            if(um[i] > 1) { 
                k = i; break;
            }
        }
        return k;
    }
};

代码二:数组模拟哈希表(耗时低,因为数组效率高)

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int a[100005] = {0};
        int k = 0;
        for(auto i : nums) {
            a[i]++;
            if(a[i] > 1) { 
                k = i; break;
            }
        }
        return k;
    }
};


解法三:原地置换

现在让我们重排这个数组。从头到尾依次扫描这个数组中的每个数字。

当扫描到下标为i的数字时,首先比较这个数字(用m表示)是不是等于i。

如果是,则接着扫描下一个数字;如果不是,则再拿它和第m个数字进行比较。

如果它和第m个数字相等,就找到了一个重复的数字(该数字在下标为i和m的位置都出现了);如果它和第m个数字不相等,就把第i个数字和第m个数字交换,把m放到属于它的位置。
接下来再重复这个比较、交换的过程,直到我们发现一个重复的数字。

以数组{2,3,1,0,2,5,3}为例来分析找到重复数字的步骤。数组的第0个数字(从0开始计数,和数组的下标保持一致)是2,与它的下标不相等,于是把它和下标为2的数字1交换。交换之后的数组是{1,3,2,0,2,5,3}。

此时第О个数字是1,仍然与它的下标不相等,继续把它和下标为1的数字3交换,得到数组{3.1.2.0.2.5.3}。

接下来继续交换第0个数字3和第3个数字0,得到数组{0.1.2.3.2.5.3}。此时第О个数字的数值为0,接着扫描下一个数字。

在接下来的几个数字中,下标为1、2、3的3个数字分别为1、2、3,它们的下标和数值都分别相等,因此不需要执行任何操作。

接下来扫描到下标为4的数字2。由于它的数值与它的下标不相等,再比较它和下标为2的数字。

注意到此时数组中下标为2的数字也是2,也就是数字2在下标为2和下标为4的两个位置都出现了,因此找到一个重复的数字。

时间复杂度为O(n),空间复杂度O(1)

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int i = 0, len = nums.size();
        while(i < len) {
            if(nums[i] == i) {
                i++;
                continue;
            }
            if(nums[i] != nums[nums[i]]) {
                swap(nums[i], nums[nums[i]]);
            } else {
                return nums[i];
            }
        }
        return -1;
    }
};


     ——朝着一个目标不断做精深练习,不断犯错,不断挑战自己的极限,这种努力给你带来的收获绝对超出你的想象

以上是关于三种解法实现剑指 Offer 03. 数组中重复的数字的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

剑指Offer03. 数组中重复的数字

剑指 Offer(第 2 版)刷题 | 03. 数组中重复的数字

剑指offer五十之数组中重复的数字