大小为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
所以我建议:
计算指数的总和(4x5 / 2 = 10)并检查值' sum(3 + 4 + 1 + 2 + 0)等于该总和。如果没有,那就有重复的号码。
除了第一个条件之外,还得到索引的乘法(除了0. so:1x2x3x4)并检查它是否等于值'乘法(0除外,因此:3x4x1x2x0)。
=>如果在每种情况下,它是相等的,那么我说没有重复的数字。否则,有一个重复的数字。
这是对的吗?如果是,请证明它或给我一个链接。否则,请反驳。
答案 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
,因此您的算法不起作用。
找一个反例 2 3 :
0
到N - 1
; M1 > 2
和M2 > 2
之间选择两个偶数 3 0
和N - 1
并将它们减半; P1 = M1/2 - 1
替换为2 * P1
,将P2 = M2/2 + 1
替换为2 * P2
。在原始数组中,您有:
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 > 2
和M2 > 2
,以便M1/2 != M2
(和相反)和M1/2 - 1 != M2/2 + 1
,对于任何大小都小于14的数组,我认为这是不可能的。
算法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)
更深入解释为什么您的算法错误:
- 计算指数之和(4x5 / 2 = 10)并检查值sum(3 + 4 + 1 + 2 + 0)是否等于此总和。如果没有,那就有重复的数字。
醇>
给定任何没有重复的数组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个,依此类推。可以肯定地说,误报的数量比实际的正面数快得多
- 除了第一个条件外,得到索引的乘法(除了0. so:1x2x3x4)并检查它是否等于值的乘法(除了0,所以:3x4x1x2x0)。
醇>
第二个要求涉及将所有指数乘以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数组/向量相同其他例子!)