leetcode287——Find the Duplicate Number

题目大意:数组大小n+1,数组内元素范围[1,n],求出重复的元素

分析:面试中一般采用前几种做法。快慢指针的做法虽然很好,但是一般想不出来,除非你之前做过这道题。

方法一:排序后找相邻元素重复的即可。时间复杂度O(nlogn)+空间复杂度O(1)。

方法二:哈希表判重。时间复杂度O(n)+空间复杂度O(n)。

方法三:和leetcode442类似。

方法四:二分查找。时间复杂度O(nlogn)+空间复杂度O(1)。二分查找O(logn),循环统计O(n)。抽屉原理,5个抽屉放6个苹果,一定有一个抽屉放了两个苹果。元素从1~n,二分法猜哪个数重复,取中位数,遍历数组统计≤中间数的元素个数,如果个数大于中间数,就说明[left,mid]中有重复元素。比如14522367,先猜4是重复数字,发现有五个≤4的元素,说明重复元素肯定在[1,4]之间。

方法五:快慢指针Floyd算法。时间复杂度O(n)+空间复杂度O(1)。由题意可知,对于数值中的每个元素,都有它能指向的有效索引,因为元素值在1~n之间,索引下标在0~n之间。用类似判断循环链表的快慢指针,第一阶段找到相交点(相交点一定在环上,但不一定时入环点),第二阶段找到进入循环的点。慢指针走一步,快指针走两步。走到元素值指向的索引下标,比如指针当前在0,nums[0]=4,所以指针走到4。Floyd算法证明参考leetcode142(寻找链表入环节点)。

代码:

方法三:

class Solution {
public:
    int findDuplicate(vector<int> &nums) {
        int ans;
        for(int i = 0;i < nums.size();i++){
            if(nums[abs(nums[i]) - 1] > 0){
                nums[abs(nums[i]) - 1] *= -1;
            }
            else ans = abs(nums[i]);
        }
        return ans;
    }
};

方法四:

class Solution {
public:
    int findDuplicate(vector<int> &nums) {
        int left = 0,right = nums.size() - 1;
        while (left < right) {
            int mid = (left + right) / 2;
            int cnt = 0;  //统计小于等于mid的个数
            for (int num:nums) {
                if (num <= mid) {
                    cnt++;
                }
            }
            if (cnt > mid) right = mid;
            else left = mid + 1;
        }
        return left;
    }
};

方法五:

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        //第一阶段:找到索引的intersection point(快指针追上了慢指针,代表有环)
        int fast = nums[nums[0]],slow = nums[0];
        while(slow != fast){
            fast = nums[nums[fast]];
            slow = nums[slow];
        }
        //第二阶段:找到入环点
        int p = 0,q = slow;
        while(p != q){
            p = nums[p];
            q = nums[q];
        }
        return p;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值