leetcode array two-pointer binary-search|287. Find the Duplicate Number

Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
Example 1:
Input: [1,3,4,2,2]
Output: 2
Example 2:
Input: [3,1,3,4,2]
Output: 3
Note:
You must not modify the array (assume the array is read only).
You must use only constant, O(1) extra space.
Your runtime complexity should be less than O(n2).
There is only one duplicate number in the array, but it could be repeated more than once.


按照题目要求数组中有n+1个数,范围是1~n,只有一个重复的数,找出这个数

要求时间复杂度不能超过O(n^2),不能使用多余的空间,不能改变原数组的值

想到过

  1. 暴力遍历   复杂度
  2. 将数组元素进行排序之后遍历    改变原数组
  3. 类似之前的题目,取负法,时间复杂度为O(n)     改变原数组

然而,简单尝试了一下暴力遍历法,居然通过了,没有超时,但我认为这种方法是不符合题目要求的

class Solution {
    public int findDuplicate(int[] nums) {
        //1.排序后遍历
        //2.像之前那样 出现过的元素取负
        //但是这两种方法都改变了元数组的值
        for(int i=0;i<nums.length;i++){
            for(int j=i+1;j<nums.length;j++){
                if(nums[i]==nums[j]) return nums[i];
            }
        }
        return 0;
    }
}

其他办法是想不到了,去向大佬们学习!

1.使用Java的内置数据结构(虽然也不符合题目的限制,但也不失为一种好方法)】

class Solution {
    public int findDuplicate(int[] nums) {
        Set<Integer> seen = new HashSet<Integer>();
        for (int num : nums) {
            if (seen.contains(num)) {
                return num;
            }
            seen.add(num);
        }

        return -1;
    }
}

2.cycle detection

https://zh.wikipedia.org/wiki/Floyd判圈算法

有两个不同的指针,一个指针走一步,另一个指针走两步,如若他们两个相遇了,那就存在环。如果走的慢的那个指针都已经走到无路可走的地步两者还没有相遇,那么就不存在环。

把两个指针放到同一个位置,一个固定,一个向前走,再次相遇的时候走的长度就是环的长度。

一个指针放到最开始的位置,另一个指针在他们相遇的地方,以相同的速度往前走,此时他们之间的距离是环长度的整数倍,以相同的速度继续往前走,两者相遇的位置就是换的入口。

在这个问题当中,按照题目所给条件,数组中元素的值和下标构成环,环的入口就是值重复的地方????

class Solution {
    public int findDuplicate(int[] nums) {
        if(nums.length<=1) return -1;
        int slow=0;
        int fast=0;
        do{
            slow=nums[slow];
            fast=nums[nums[fast]];
        }while(nums[slow]!=nums[fast]);
        fast=0;
        while(slow!=fast){
            slow=nums[slow];
            fast=nums[fast];
        }
        return slow;
    }
}

以题目给出的第一个例子为例

遍历情况为1->3->2->4->2,相当于是2,4形成一个环,那么如果画成环遍历的话,2被遍历到了2遍

所以环的入口为重复的元素,图片不知道为啥转不过来了(逃

巧用while 和do-while~

猜你喜欢

转载自blog.csdn.net/xueying_2017/article/details/81381247