LeetCode 287. 寻找重复数 多解法

LeetCode 287. 寻找重复数

原题地址:

https://leetcode-cn.com/problems/find-the-duplicate-number/comments/

在这里插入图片描述
题目不难但是挺巧妙的,而且解法很多,可以学习一下。

在 n + 1 个元素的数组里,放[1 , n]之间的元素,由于抽屉原理(又见抽屉原理)那么我们知道,一定会有至少一个重复元素,而题目规定是刚好一个重复元素,所以找到这个重复元素。
ps : 注意限制条件,难点就在限制条件。

  1. 解法一(判环):
    我们把数组记录的数看成对应的数组索引,那么如果是n个不同的数,那就是一根长度为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;
        }
        while (true){
            slow = nums[slow];
            fast = nums[fast];
            if(slow == fast) return nums[slow];
        }
    }
};
  1. 解法二(位运算)
    位运算解法,在LeetCode我看用这个解法的比较少,但我觉得这个解法最好想。1—n 的数二进制的每一位 1 的个数应该是确定的,找到每一位多出的 1 就能组成重复的那个数。

参考代码二:

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int n = nums.size(); // 这个n实际上是n + 1;
        int ans = 0;
        for(int i = 0 ; i < 32 ; i++){
            int k = 1 << i;
            int cnt1 = 0, cnt2 = 0;
            for(int j = 0 ; j < n ; j++){
                if(k & j) cnt1++; // 这里算了0 —— n但0不影响; 
                if(k & nums[j]) cnt2++;
            }
            if(cnt2 > cnt1) ans += k;
        }
        return ans;
    }
};
  1. 解法三(二分)

在1 — n 之间二分,我们可以知道如果没有重复的数那么数组中小于mid的数的个数一定等于mid,如果大于mid,那么我们就可以知道重复的数一定在[l , mid]这个范围内,所以二分找到这个数就好了。

参考代码三:

class Solution {
public:
    bool check(int m,vector<int>& nums){
        int cnt = 0;
        for(int i = 0 ; i < nums.size() ; i++){
            if(nums[i] <= m) cnt++;
        }
        return cnt > m;
    }
    int findDuplicate(vector<int>& nums) {
        int l = 1 , r = nums.size() - 1;
        int ans = 0;
        while (l <= r){
            int mid = (l + r) >> 1;
            if(check(mid,nums)){
                ans = mid;
                r = mid - 1;
            } else l = mid + 1;
        }
        return ans;
    }
};

看似简单的题有时候也能带来很多思维启发,值得注意。

发布了23 篇原创文章 · 获赞 7 · 访问量 1740

猜你喜欢

转载自blog.csdn.net/weixin_44164153/article/details/104921962