在数组中找到重复的数字

时间:2015-10-19 05:08:20

标签: c++ algorithm find

我正在调试以下问题并发布我正在调试和处理的解决方案,解决方案或类似的问题发布在几个论坛上,但我认为解决方案有一个错误,当num [0] = 0或一般数字[x] = x?我对么?如果我错了,请随时纠正我。

给定包含n + 1个整数的数组nums,其中每个整数在1和n之间(包括1和n),证明必须存在至少一个重复的数字。假设只有一个重复的数字,找到重复的数字。

注意: 您不能修改数组(假设该数组是只读的)。 您必须仅使用常量O(1)额外空间。 您的运行时复杂度应小于O(n2)。 数组中只有一个重复的数字,但它可以重复多次。

int findDuplicate3(vector<int>& nums)
{
    if (nums.size() > 1)
    {
        int slow = nums[0];
        int fast = nums[nums[0]];
        while (slow != fast)
        {
            slow = nums[slow];
            fast = nums[nums[fast]];
        }

        fast = 0;
        while (fast != slow)
        {
            fast = nums[fast];
            slow = nums[slow];
        }
        return slow;
    }
    return -1;
}

4 个答案:

答案 0 :(得分:7)

以下是我的代码,它使用 Floyd的循环查找算法

#include <iostream>
#include <vector>
using namespace std;

int findDup(vector<int>&arr){
    int len = arr.size();
    if(len>1){
        int slow = arr[0];
        int fast = arr[arr[0]];
        while(slow!=fast){
            slow = arr[slow];
            fast = arr[arr[fast]];
        }
        fast = 0;
        while(slow!=fast){
            slow = arr[slow];
            fast = arr[fast];
        }
        return slow;
    }
    return -1;
}

int main() {
    vector<int>v = {1,2,2,3,4};
    cout<<findDup(v)<<endl;
    return 0;
}

注释这是有效的,因为不允许使用零,因此数组的第一个元素不是循环的一部分,因此我们找到的第一个循环的第一个元素都被引用循环内外。如果允许零,如果arr [0]处于循环中,则会失败。例如,[0,1,1]。

答案 1 :(得分:3)

从1到N = $("#header_menuId li").on('mouseover',function(){ $(this).animate({ height: '+=150px', width: '+=150px' }); }).on('mouseout',function(){ $(this).animate({ height: '-=150px', width: '-=150px' }); 的整数之和。您可以使用它来查找重复 - 对数组中的整数求和,然后从总和中减去上面的公式。这是副本。

更新:上述解决方案基于(可能无效)假设输入数组由1到N的值加上单个副本组成。

答案 2 :(得分:1)

由于您无法使用任何额外空间,因此将排除使用其他哈希表。

现在,对现有阵列进行散列处理,如果允许我们修改阵列就可以实现。

  

ALGO:

1)从第一个元素开始。

2)散列第一个元素并对hash的值应用转换。让我们说这个转换正在产生值-ve。

3)继续下一个元素。散列元素并在应用转换之前,检查是否已经应用了转换。

4)如果是,则元素是重复的。

代码:

 for(i = 0; i < size; i++)
  {
    if(arr[abs(arr[i])] > 0)
      arr[abs(arr[i])] = -arr[abs(arr[i])];
    else
      cout<< abs(arr[i]) <<endl;
  }  

这种转换是必需的,因为如果我们要使用散列方法,则必须存在冲突才能对相同的密钥进行散列。

我无法想到一种可以在没有任何额外空间且不修改数组的情况下使用散列的方法。

答案 3 :(得分:1)

  1. 从指向第一个元素的两个指针开始: fast slow
  2. 将“移动”定义为将快速增加2步(位置),将慢速增加1。
  3. 每次移动后,检查&amp; 快速指向同一节点。
  4. 如果有循环,他们会在某个时刻。这是因为在它们都处于循环中之后, fast 的移动速度是 slow 的两倍,最终会“碰到”它。
  5. 说他们在 k移动之后见面。这不是重复的元素,因为它可能不是从循环外部到达的循环的第一个元素。
    将此元素称为 X
  6. 请注意, fast 已经 2k 次,已经步入 k 次。
  7. 快速移回零。
  8. 每一步重复推进快速,并在每一步之后进行比较。
  9. 请注意,在另一个 k 步骤之后,慢速将总共移动 2k 步骤并且快速总计 k < / em>从一开始就是步骤,因此他们将再次指向 X
  10. 请注意,如果上一步是针对它们的循环,则它们都指向 X-1 。如果前面的步骤仅在 slow 的循环中,则它们指向不同的元素。
  11. 同样适用于 X-2,X-3, ......
  12. 所以在前进的过程中,他们第一次指向相同的元素是从循环外部到达的循环的第一个元素,这是你正在寻找的重复元素。