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

找出数组中重复的数字。

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

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

解题思路:

这题为了降低时间复杂度,我们可以采用原地置换的方式,方法的思维和一个萝卜一个坑比较类似

  • 首先,我们来看没有重复数字的数组 nums: 3 1 0 2
nums[i]     3  1  0  2   萝卜   
    i       0  1  2  3   

0号坑说:我不要三号萝卜,我要自己的0号萝卜,因此请求和第三号坑的萝卜进行交换,然后变成这样

nums[i]     2  1  0  3   萝卜  
    i       0  1  2  3   

0号坑发现自己还没有找到萝卜,于是又请求与二号坑的萝卜进行交换

nums[i]     0  1  2  3   萝卜 
    i       0  1  2  3   

这样,刚好所有的萝卜与坑都是一一对应的,因此退出循环

  • 然后,我们来看有重复数字的数组nums: 1 2 3 2
nums[i]     1  2  3  2    萝卜
    i       0  1  2  3    

同样的,0号坑不要1号萝卜,请求与1号坑交换

nums[i]     2  1  3  2    萝卜
    i       0  1  2  3    

0号坑不要2号萝卜,请求与2号坑交换

nums[i]     3  1  2  2    萝卜
    i       0  1  2  3    

0号坑不要3号萝卜,请求与3号坑交换

nums[i]     2  1  2  3    萝卜
    i       0  1  2  3    

0号坑不要2号萝卜,请求与2号坑交换,但是发现2号坑也是2号萝卜,交换没有意义,直接退出循环,返回当前值(说明出现了重复元素)

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

AC代码

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int temp;
        for (int i = 0; i < nums.size(); i++){
            while (nums[i] != i){
                //发现自己的萝卜和要请求交换的坑的萝卜相同,说明有重复数字出现
                if(nums[i] == nums[nums[i]]){
                    return nums[i];
                }
                //交换萝卜
                temp = nums[i];
                nums[i] = nums[temp];
                nums[temp] = temp;
            }
        }
        //所有的数字都在自己应该在的位置上,说明没有重复元素
        return -1;
    }
};

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

剪绳子 Previous
线程池 Next