《剑指offer》面试题03. 数组中重复的数字

问题描述

找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3 
限制:
2 <= n <= 100000

这道题和leetcode 287. 寻找重复数相似:

代码1

时间复杂度\(O(N)\),空间复杂度\(O(N)\).

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

结果:

执行用时 :116 ms, 在所有 C++ 提交中击败了17.01%的用户
内存消耗 :24 MB, 在所有 C++ 提交中击败了100.00%的用户

代码2

如果允许移动数据,时间复杂度为\(O(N\log(N))\),空间复杂度为\(O(1)\):

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

结果:

执行用时 :132 ms, 在所有 C++ 提交中击败了12.97%的用户
内存消耗 :23.3 MB, 在所有 C++ 提交中击败了100.00%的用户

代码3

如果允许修改数据,时间复杂度为\(O(N)\),空间复杂度为\(O(1)\):

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int i,n = nums.size(),j;
        for(i = 0; i < n; ++i)
        {
            j = abs(nums[i]);
            if(nums[j] < 0)return j;
            else nums[j] = -nums[j];
        }
        //因为一定有重复的数字,前面如果没有退出程序的话说明重复的是0
        return 0;
    }
};

结果:

执行用时 :92 ms, 在所有 C++ 提交中击败了28.16%的用户
内存消耗 :22.8 MB, 在所有 C++ 提交中击败了100.00%的用户

代码4

如果允许移动数据,时间复杂度为\(O(N)\),空间复杂度为\(O(1)\):

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int i,n = nums.size(),j;
        for(i = 0; i < n; ++i)
        {
            //我不在该在的地方,我该在的地方不是我
            while(nums[i] != i && nums[i] != nums[nums[i]])
                swap(nums[i],nums[nums[i]]);
            //我不在该在的地方,我该在的地方还有我
            if(nums[i] != i && nums[i] == nums[nums[i]])
                break;
        }
        return nums[i];
    }
};

结果:

执行用时 :92 ms, 在所有 C++ 提交中击败了28.16%的用户
内存消耗 :23.1 MB, 在所有 C++ 提交中击败了100.00%的用户

代码5

如果不允许移动数据,不允许修改数据,时间复杂度为\(O(N\log(N))\),空间复杂度为\(O(1)\),注意不能简单的写为

int findRepeatNumber(vector<int>& nums) {
        int i,n = nums.size(),left = 1,right = n,middle,num;
        while(left < right)
        {
            middle=left+(right-left)/2;
            cout<<"("<<left<<","<<middle<<","<<right<<")"<<endl;
            num = 0;
            for(i = 0; i < n; ++i)
                if(nums[i]+1 <= middle) 
                    ++num;
            cout<<" "<<num<<endl;
            if(num <= middle)
                left = middle+1;
            else 
                right = middle;
        }
        return left-1;
    }
};

反例[0, 1, 2, 3, 4, 11, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],上面的写法适宜于写\(n+1\)个在1到n之间的元素,即不缺元素,这个例子缺个5.正确写法待思考。

posted @ 2020-04-07 21:26  曲径通霄  阅读(194)  评论(0编辑  收藏  举报