我们如何在 O(n) 时间和 O(1) 空间复杂度内找到数组中的重复数字

Posted

技术标签:

【中文标题】我们如何在 O(n) 时间和 O(1) 空间复杂度内找到数组中的重复数字【英文标题】:How can we find a repeated number in array in O(n) time and O(1) space complexity 【发布时间】:2011-09-10 10:02:44 【问题描述】:

我们如何在 O(n) 时间和 O(1) 复杂度内找到数组中的重复数字? 例如 数组 2,1,4,3,3,10 输出为 3

编辑: 我尝试了以下方式。 我发现如果 no 奇怪地重复,那么我们可以通过执行 xor 来实现结果。所以我想使奇数的元素不重复甚至不重复,并且每个均匀重复的不重复。但是为此,我需要从 O(n) 中的输入数组中找出唯一的元素数组,但找不到方法。

【问题讨论】:

空间复杂度为 O(1) 我不知道你为什么有 data-structures 标签。 【参考方案1】:

假设数组中的数字值有一个上限(我曾经使用过的所有编程语言中的所有内置整数类型都是这种情况——例如,假设它们是 32 -bit 整数)有一个使用常量空间的解决方案:

    创建一个包含 N 个元素的数组,其中 N 是输入数组中整数值的上限,并将所有元素初始化为 0false 或类似的值。我将其称为 lookup 数组。 循环输入数组,并使用每个数字来索引查找数组。如果您找到的值为1true(等),则输入数组中的当前数字是重复的。 否则,将查找数组中的对应值设置为1true,以记住我们已经看到了这个特定的输入数字。

技术上,这是 O(n) 时间和 O(1) 空间,它不会破坏输入数组。实际上,您需要按自己的方式运行这样的程序才能真正运行(例如,如果在输入中谈论 64 位整数是不可能的)。

【讨论】:

是的,我也想到了那个解决方案,但复杂度是 O(K*n),其中 k 不是比特数。如果 k>logn,那么 O(nlogn) 将是有效的解决方案。 这个解决方案在空间中的 O(1) 怎么样?如果我们有 0,1,2,3... 2^32-1,2^32-1 作为输入,则需要一个大小为 2^32 位的数组,大小等于 = 2^27 个整数.这肯定不是 O(1)。 @NitinGarg:你对 O(1) 的定义是错误的。这个解决方案需要一个大小为2^32的数组不管输入是什么,因此它是O(1)。 @Jon - 通过同样的技术,您可以迭代数组 2^32 次,每次迭代都会查找单个数字的重复项(仅使用布尔值来存储我是否找到了一个,并且如果我找到另一个,那么我有一个副本)。从技术上讲,它是 O(n),当然也是 O(1) 空间。 @Jon - 对于整数排序,我可以创建一个包含 2^32 个元素的数组 X,所有元素都初始化为 0。现在我遍历整数的原始序列 (a1,a2...ai. .. a) 并在每一步将 X[ai] 加 1。最后,我只需要在 X 上进行一个循环,花费 n + 2^32(恒定时间)来获得排序后的序列。【参考方案2】:

如果不了解数组中可能的值的更多信息,您将无法做到。

对于 O(1) 空间要求,最快的方法是对数组进行排序,使其至少为 O(n*log(n))。

【讨论】:

【参考方案3】:

使用位操作...在一个循环中遍历列表。

    通过移动 i 的值来检查掩码是否为 1。 如果是这样,打印出重复值 i。 如果未设置该值,请设置它。

*如果您只想显示一个重复值一次,请添加另一个整数显示并设置其位,如下例所示。

**这是在 java 中,我不确定我们是否会达到它,但您可能还想使用 Integer.MAX_VALUE 添加检查。

    public static void repeated( int[] vals ) 
        int mask = 0;
        int show = 0;
        for( int i : vals ) 
            // get bit in mask
            if( (( mask >> i ) & 1) == 1 &&
                (( show >> i ) & 1) == 0 )
            
                System.out.println( "\n\tfound: " + i );
                show = show | (1 << i);
            

            // set mask if not found
            else
            
                mask = mask | (1 << i);
                System.out.println( "new: " + i );
            

            System.out.println( "mask: " + mask );
        
    

【讨论】:

别忘了这个逻辑只有在你有一种类型的值时才有效,要么都是正的,要么是负的。对于 (-17, 15) 等值,上述操作将失败【参考方案4】:

如果不知道有关输入数组的任何限制规则,这是不可能的,要么内存复杂度会依赖于输入大小,要么时间复杂度会更高。

上面的 2 个答案实际上是接近您所要求的最佳答案,一个权衡是时间,第二个权衡是在内存中,但您不能让它在 O(n) 时间和 O(1 ) 某些未知输入数组中的复杂性。

【讨论】:

【参考方案5】:

我也遇到了这个问题,我的解决方案是使用 hashMap 。python 版本如下:

  def findRepeatNumber(lists):
      hashMap = 
      for i in xrange(len(lists)):
          if lists[i] in hashMap:
              return lists[i]
          else: 
              hashMap[lists[i]]=i+1
      return

【讨论】:

他想要一个 o(1) 空间。你的空间是 o(n) ;)【参考方案6】:

只有当你有特定的数据时才有可能。例如,所有数字的范围都很小。然后您可以将重复信息存储在源数组中,而不影响整个扫描和分析过程。

简化示例:您知道所有数字都小于 100,然后您可以使用额外的零标记数字的重复计数,例如当 9 出现两次时将 900 代替 9。

当 NumMax-NumMin 时很容易

http://www.geeksforgeeks.org/find-the-maximum-repeating-number-in-ok-time/

【讨论】:

【参考方案7】:
public static string RepeatedNumber()
    
        int[] input = 66, 23, 34, 0, 5, 4;
        int[] indexer = 0,0,0,0,0,0
        var found = 0;
        for (int i = 0; i < input.Length; i++)
        
            var toFind = input[i];
            for (int j = 0; j < input.Length; j++)
            
                if (input[j] == toFind && (indexer[j] == 1))
                
                    found = input[j];
                
                else if (input[j] == toFind)
                
                    indexer[j] = 1;
                
            

        


    return $"most repeated item in the array is found";

【讨论】:

O(n^2) 时间【参考方案8】:

你可以这样做

#include<iostream.h>
#include<conio.h>
#include<stdio.h>
void main ()

    clrscr();
    int array[5],rep=0;
    for(int i=1; i<=5; i++)
    
        cout<<"enter elements"<<endl;
        cin>>array[i];
    
    for(i=1; i<=5; i++)
    
        if(array[i]==array[i+1])
        
            rep=array[i];
        
    
    cout<<" repeat value is"<<rep;
    getch();

【讨论】:

你确定你得到答案了吗?如果重复的数字不在一起怎么办?

以上是关于我们如何在 O(n) 时间和 O(1) 空间复杂度内找到数组中的重复数字的主要内容,如果未能解决你的问题,请参考以下文章

时间复杂度和空间复杂度计算

二叉树神级遍历方法

时间复杂度和空间复杂度

斐波拉契数列加强版——时间复杂度O,空间复杂度O

时间复杂度和空间复杂度

时间复杂度和空间复杂度