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

100 阅读1分钟

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

1. 题目描述

找出数组中重复的数字。

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

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

限制:

2 <= n <= 100000

2. 解题思路

因为n个数并且范围落在0-n-1这个区间内,假设如果没有重复的数字,那么应该刚好有0,1,2,···n-1个数落在0-n-1这个数组下标区间内,如果对其进行排序,应该数组元素的值刚好对应数组下标的值。由于本题明确说明了在其他条件不变的情况下,有些数字是重复的,在此条件下找到重复的元素。

所以第一考虑排序,然后得到重复的元素,但排序的时间复杂度过高,并且排序过后找到重复元素,其实也可以采用二分查找,如果发现,元素比元素下标要小,那么左边一定有重复元素,而如果元素与元素下标相等,那么左右两边都可能会有重复元素,而大于的情况不可能; 但是这样的二分查找运气好可以确定一个比较小的区间,运气不好需要不断挑选判断点。而在要求只找到一个重复元素的情况下,是否可以考虑在排序的过程中,利用元素下标相等来排除不可能重复的元素,或者说在排序中,划分哪些排好序的元素不重复,哪些尚未排序的可能有重复元素。

因此我们考虑不断置换元素,使元素落在与数组下标相等的位置,这样,有点类似在数组内形成了一个map映射。这样不断置换元素,当发现某个需要置换的元素,其数组下标位置已经有了元素值得时候,便得到了结果。

其实这种思路本质上就是利用map映射。

3. 解题思路

// 使用map映射解决问题,从头到尾遍历,将nums[i]的值作为键,i作为值存入mp中,,一旦发现有nums[i]与mp中的键相同,那么便找到了一个重复点元素

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        map<int,int> mp;
        map<int,int>::iterator iter;
        for(int i=0;i<nums.size();i++){
            iter=mp.find(nums[i]);
            if(iter!=mp.end()){
                // cout<<nums[i]<<endl;
                // cout<<"Find, the key is"<<iter->first<<endl;
                // cout<<"Find, the value is"<<iter->second<<endl;
                return nums[i];
            }else{
                mp[nums[i]]=i;  //键 值对,find寻找键
                // cout<<nums[i]<<endl;
            }
        }
        return -1;
    }
};
//利用数组本身的特性,构建一个在数组内的map映射,来解决问题

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