zoukankan      html  css  js  c++  java
  • [leetcode] 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:

    1. You must not modify the array (assume the array is read only).
    2. You must use only constant, O(1) extra space.
    3. Your runtime complexity should be less than O(n2).
    4. There is only one duplicate number in the array, but it could be repeated more than once.

    分析:这个题目翻译一下:数组长度为n的数组中,所有的元素都在1~n中间,假设只有一个重复的数字,这个数字可以重复很多次,求这个数字。
    看Note,要求很高,最关键的要求就是不能更改数组,时间复杂度,空间复杂度都有要求。
    首先我们降低一下难度,如果可以更改数组,根据上一篇笔记,有三种可行的方法:取反法,交换法,取余法。因为取余法比较容易理解和实现,而且使用范围特别广,不妨用取余法先来解决一下。代码如下:
     1 class Solution {
     2     public int findDuplicate(int[] nums) {
     3         int n = nums.length;
     4         for ( int i = 0 ; i < nums.length ; i ++ ){
     5             nums[ (nums[i] - 1) % n ] += n;
     6         }
     7         for ( int i = 0 ; i < nums.length ; i ++ ){
     8             nums[i] = (nums[i] - 1) /  n ;
     9             if ( nums[i] >= 2 ) return i+1;
    10         }
    11         return -1;
    12     }
    13 }

          运行时间1ms,也是很快的算法了。但是问题就是改动了数组,因此下面就使用Floyd算法来做。


    思路二:使用Floyd算法。
    算法过程:
    Floyd算法分为两个不同的阶段。第一个阶段是判断在链表中是否有环路,如果不存在就马上返回空,也就不存在第二阶段。第二个阶段就是找到环路的入口。
    第一阶段:
    初始化两个指针(快的兔子hare)和(慢的乌龟tortoise)。接下来,兔子hare和乌龟tortoise从同一个节点出发(头节点),乌龟tortoise每次走一个节点,兔子hare每次走两个节点。
    如果他们在前进若干步后在同一个节点相遇,我们就返回这个节点,如果最终没有返回节点信息,而是返回空,则代表不存在环路。
    第二阶段:
    由于第一阶段确定了有环路,第二阶段就是找环的入口节点。接下来初始化两个个指针,ptr1:它指向头节点, ptr2:指向第一阶段找到的相遇节点。
    然后将他们以一次移动一个节点的速度向前移动,直到他们再次相遇为止,并返回这个节点。
    具体的算法证明在:印象笔记->leetcode->listnode中。
    代码如下:
     1 class Solution {
     2    public int findDuplicate(int[] nums) {
     3         int tortoise = nums[0];  //跑的慢的节点
     4         int hare = nums[0]; //跑的快的节点
     5 
     6         //第一个步骤,找到相遇点
     7         //因为有1个重复的数组,所以肯定有“环
     8         while ( true ){
     9             tortoise = nums[tortoise];
    10             hare = nums[nums[hare]];
    11             if ( hare == tortoise ) break;
    12         }
    13 
    14         //第二个步骤,找到环入口
    15         int ptr1 = nums[0];
    16         int ptr2 = tortoise;
    17         while ( ptr1 != ptr2 ){
    18             ptr1 = nums[ptr1];
    19             ptr2 = nums[ptr2];
    20         }
    21         return ptr1;
    22     }
    23 }

          运行时间0ms。其实这个算法可以作为Two Pointer的一个情况。

          类似问题:[leetcode]141. Linked List Cycle

                           [leetcode]142. Linked List Cycle II

  • 相关阅读:
    iOS-技巧性总结
    使用Xcode进行调试
    iOS-屏幕适配-UI布局
    iOS开发简单介绍
    iOS-网络处理
    iOS-数据解析XML解析的多种平台介绍
    iOS-数据持久化基础-JSON与XML数据解析
    iOS-数据持久化-第三方框架FMDB的使用
    ASP.NET的内置对象
    线性表
  • 原文地址:https://www.cnblogs.com/boris1221/p/9355304.html
Copyright © 2011-2022 走看看