剑指offer Leetcode 3.数组中重复的数字 + 287.寻找重复数

image-20201121153506997

注意:要问面试官时间/空间以及是否能修改原数组的需求。

解法1:排序然后找出重复的数字,时间复杂度O(nlogn) 不需要额外空间

解法2:哈希表,unordered_set。

解法3:数组实现哈希表,因为规定了所有数字都在0~n-1范围内。时间复杂度O(n),空间复杂度O(n)

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

解法4:原地哈希,不需要额外空间,时间复杂度为O(n)

●数字nums[i] 应该放在下标为 i 的位置上,这就像是我们人为编写了哈希函数,这个哈希函数的规则还特别简单;
而找到重复的数就是发生了哈希冲突;

●类似问题还有「力扣」第 41 题: 缺失的第一个正数、「力扣」第 442 题: 数组中重复的数据、「力扣」第 448 题: 找到所有数组中消失的数字 。

class Solution {
    
    
public:
    int findRepeatNumber(vector<int>& nums) {
    
    
        for(int i = 0; i < nums.size(); i++){
    
    
            while(nums[i] != i){
    
    
                //nums[i]应该放在下标为nums[i]的位置上,如果重复则找到元素
                if(nums[nums[i]] == nums[i])
                    return nums[i];
            	//不重复则把nums[i]放到该放的地方
                swap(nums[nums[i]], nums[i]);
            }
        }
        return -1;
    }
};

 题目如果变为长度为n+1个整数数组数字在1到n之间(包括1和n),可以用二分查找做,因为上面0到n-1有n个数,可能会出现缺少的数和重复的数出现在一边,没法缩小范围。

 此题中原地哈希仍然适用,但是不符合不能修改原数组的需求。

image-20201121215848072

解法1:二分查找:时间换空间的做法,不常用,不过可以满足题目不能更改数组,且不能使用额外空间的需求

class Solution {
    
    
public:
    int cnt(vector<int>& nums, int mid){
    
    
        int res = 0;
        for(int i : nums)
            if(i <= mid)
                res++;
        return res;
    }
    int findDuplicate(vector<int>& nums) {
    
    
        if(nums.size() < 2)
            return -1;
        int left = 1, right = nums.size() - 1;
        while(left < right){
    
    
            int mid = left + (right - left) / 2;
            //如果<=mid的数<=mid,如<=4的数只有4个,那么重复的数比4大
            if(cnt(nums, mid) <= mid)
                left = mid + 1;
            else
                right = mid;
        }
        return left;
    }
};

解法2:快慢指针

双指针解法,可以将数组看成一个链表,类似于环形链表找环入口,快指针肯定追上慢指针,L = m +n

class Solution {
    
    
public:
    int findDuplicate(vector<int>& nums) {
    
    
        int slow = 0, fast = 0;
        while(true){
    
    
            slow = nums[slow];
            fast = nums[nums[fast]];
            if(slow == fast)
                break;
        }
        fast = 0;
        while(true){
    
    
            slow = nums[slow];
            fast = nums[fast];
            if(slow == fast)
                break;
        }
        return slow;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_36459662/article/details/113924801