数组中是否有重复的数字?

时间:2016-08-11 12:05:42

标签: c++ arrays numbers repeat

大小为n的数组。值可以在0和(n-1)之间作为索引。

例如:array[4] = {0, 2, 1, 3}

我应该说,如果有任何数字重复超过1次。

例如:array[5] = {3,4,1,2,4} - >返回true因为重复了4次。

这个问题有很多不同的解决方案,我想知道这个具体的解决方案是否正常(如果是,请证明,否则反驳)。

我的解决方案(让我们看看下一个例子):

array: indices   0   1   2   3   4
       values    3   4   1   2   0

所以我建议:

  1. 计算指数的总和(4x5 / 2 = 10)并检查值' sum(3 + 4 + 1 + 2 + 0)等于该总和。如果没有,那就有重复的号码。

  2. 除了第一个条件之外,还得到索引的乘法(除了0. so:1x2x3x4)并检查它是否等于值'乘法(0除外,因此:3x4x1x2x0)。

    =>如果在每种情况下,它是相等的,那么我说没有重复的数字。否则,有一个重复的数字。

  3. 这是对的吗?如果是,请证明它或给我一个链接。否则,请反驳。

4 个答案:

答案 0 :(得分:4)

为什么你的算法错了?

你的解决方案是错误的,这是一个反例(可能有更简单的例子,但我发现这个很快):

int arr[13] = {1, 1, 2, 3, 4, 10, 6, 7, 8, 9, 10, 11, 6}; 

总和为78,产品为479001600,如果您使用大小为13的正常数组:

int arr[13] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

它的总和为78,产品为479001600,因此您的算法不起作用。

如何找到反例? 1

找一个反例 2 3

  1. 0N - 1;
  2. 取一个数组
  3. M1 > 2M2 > 2之间选择两个偶数 3 0N - 1并将它们减半;
  4. P1 = M1/2 - 1替换为2 * P1,将P2 = M2/2 + 1替换为2 * P2
  5. 在原始数组中,您有:

     Product = M1 * P1 * M2 * P2
    
     Sum = 0 + M1 + P1 + M2 + P2
         = M1 + M1/2 - 1 + M2 + M2/2 + 1
         = 3/2 * (M1 + M2)
    

    在新阵列中你有:

    Product = M1/2 * 2 * P1 + M2/2 * 2 * P2
            = M1 * P1 * M2 * P2
    
    Sum = M1/2 + 2P1 + M2/2 + 2P2
        = M1/2 + 2(M1/2 - 1) + M2/2 + 2(M2/2 + 1)
        = 3/2 * M1 - 2 + 3/2 * M2 + 2
        = 3/2 * (M1 + M2)
    

    因此两个数组都有相同的总和和乘积,但是有一个重复值,所以你的算法不起作用。

    1 这是查找反例的一种方法,可能还有其他方法( 可能是其他人)。

    2 这与我用来查找第一个计数器示例的方法不完全相同 - 在原始方法中,我只使用了一个数字M并使用了这个事实您可以在不更改产品的情况下将0替换为1,但我建议使用更通用的方法以避免诸如"但我可以添加0的检查在我的算法中。"

    3 该方法不适用于小数组,因为您需要找到2个偶数M1 > 2M2 > 2,以便M1/2 != M2(和相反)和M1/2 - 1 != M2/2 + 1,对于任何大小都小于14的数组,我认为这是不可能的。

    哪些算法有效? 4

    算法1: O(n)时间和空间复杂性。

    如果您可以分配一个大小为N的新数组,那么:

    template <std::size_t N>
    bool has_repetition (std::array<int, N> const& array) {
        std::array<bool, N> rep = {0};
        for (auto v: array) {
            if (rep[v]) {
                return true;
            }
            rep[v] = true;
        }
        return false;
    }
    

    算法2: O(nlog(n))时间复杂度和O(1)空间复杂度,带有可变数组。

    您可以简单地对数组进行排序:

    template <std::size_t N>
    bool has_repetition (std::array<int, N> &array) {
        std::sort(std::begin(array), std::end(array));
        auto it = std::begin(array);
        auto ne = std::next(it);
        while (ne != std::end(array)) {
            if (*ne == *it) {
                return true;
            }
            ++it; ++ne;
        }
        return false;
    }
    

    算法3: O(n^2)时间复杂度和O(1)空间复杂度,非可变数组。

    template <std::size_t N>
    bool has_repetition (std::array<int, N> const& array) {
        for (auto it = std::begin(array); it != std::end(array); ++it) {
            for (auto jt = std::next(it); jt != std::end(array); ++jt) {
                if (*it == *jt) {
                    return true;
                }
            }
        }
        return false;
    }
    

    4 这些算法确实有效,但可能存在其他表现更好的算法 - 这些只是我能想到的最简单的算法,给出了一些&#34;限制&#34;。

答案 1 :(得分:2)

您的方法有什么问题?

您的方法计算数据的一些统计数据,并将它们与排列预期的数据进行比较(=正确答案)。虽然违反任何这些比较是决定性的(数据不能满足约束条件),但反过来不一定是这种情况。您只能查看两个统计信息,这些信息对于足够大的数据集来说太少了。由于数据是整数,因此方法可能失败的最小数据量大于3。

答案 2 :(得分:0)

如果您在数组中搜索重复项,则有一种简单的方法:

int N =5;
int array[N] = {1,2,3,4,4};

for (int i = 0; i< N; i++){
    for (int j =i+1; j<N; j++){
        if(array[j]==array[i]){
            std::cout<<"DUPLICATE FOUND\n";
            return true;
        }
    }
}
return false;

查找重复项的其他简单方法是使用std :: set容器,例如:

std::set<int> set_int;
set_int.insert(5);
set_int.insert(5);
set_int.insert(4);
set_int.insert(4);
set_int.insert(5);
std::cout<<"\nsize "<<set_int.size();

输出将为2,因为有2个单独的值

答案 3 :(得分:0)

更深入解释为什么您的算法错误:

  
      
  1. 计算指数之和(4x5 / 2 = 10)并检查值sum(3 + 4 + 1 + 2 + 0)是否等于此总和。如果没有,那就有重复的数字。
  2.   

给定任何没有重复的数组A,很容易创建一个满足第一个要求但现在包含重复项的数组。只需取两个值并将其中一个值减去某个值v,然后将该值添加到另一个值。或者采用多个值并确保它们的总和保持不变。 (只要新值仍在0 .. N-1范围内。)对于N = 3,已经可以将{0,1,2}更改为{1,1,1}。对于大小为3的数组,有7个具有正确总和的组合,但1是假阳性。对于大小为4的数组,44个中有20个具有重复项,对于大小为5的数组,其中381个为261个,对于大小为6的数组,4332中为3612个,依此类推。可以肯定地说,误报的数量比实际的正面数快得多

  
      
  1. 除了第一个条件外,得到索引的乘法(除了0. so:1x2x3x4)并检查它是否等于值的乘法(除了0,所以:3x4x1x2x0)。
  2.   

第二个要求涉及将所有指数乘以0。很容易意识到,这也许永远不会是一个非常强大的限制。只要其中一个索引不是素数,所有索引的乘积就不再唯一地与被乘数相关联,并且列表可以由具有相同结果的不同值构成。例如。一对2和6可以用3和4代替,2和9可以用6和3代替,依此类推。显然,当数组大小变大时,误报数增加,更多的非素数值被用作被乘数。

这些要求都没有真正强大,也无法弥补其他要求。由于第二个限制甚至不考虑0,因此对于从大小5开始的数组,可以相当容易地创建误报。任何一对0和4都可以简单地用任何唯一数组中的两个2​​替换,例如{2, 1, 2, 3, 2}

您需要的是获得唯一紧密的结果。您可以将第二个要求调整为更复杂的方法,并跳过非素数值并考虑0。例如,你可以使用第一个素数作为被乘数(2)作为0,使用3作为被乘数作为1,5作为被乘数作为2,依此类推。这样可行(你不需要第一个要求),但这种方法过于复杂。获得唯一结果的更简单方法是OR每个值的第i位(0 =&gt; 1 << 0,1 =&gt; 1 << 1,2 =&gt; { {1}},等等。(显然,检查已经由重复发生的值设置了一点,而不是等待最终结果更快。这在概念上与使用来自的一个bool数组/向量相同其他例子!)