在 4 sum 问题中查找代码失败的测试用例
Posted
技术标签:
【中文标题】在 4 sum 问题中查找代码失败的测试用例【英文标题】:Finding a testcase which fails the code in the 4 sum problem 【发布时间】:2019-11-26 20:50:45 【问题描述】:我们需要找出一个和等于常数k的数组中是否存在4个数字a、b、c和d(所有数字都应该在不同的索引处)。
现在它的基于散列的解决方案是这样的:创建一个散列,其键为数组中每对的总和,值作为索引对的数组,其总和为键。现在遍历数组中的每一对,并尝试在我们创建的哈希表中找到剩余的总和,同时检查是否有 2 个索引应该是共同的。
虽然上述解决方案很好,但我在 geeksforgeeks.com 上看到的解决方案是这样做的:在哈希表中,值是一对而不是对数组。它只存储最后一个总和的对。它显然对我来说看起来不对,但我仍然找不到失败的测试用例。
他们的代码:
// A hashing based CPP program to find if there are
// four elements with given sum.
#include <bits/stdc++.h>
using namespace std;
// The function finds four elements with given sum X
void findFourElements (int arr[], int n, int X)
// Store sums of all pairs in a hash table
unordered_map<int, pair<int, int>> mp;
for (int i = 0; i < n-1; i++)
for (int j = i+1; j < n; j++)
mp[arr[i] + arr[j]] = i, j;
// Traverse through all pairs and search
// for X - (current pair sum).
for (int i = 0; i < n-1; i++)
for (int j = i+1; j < n; j++)
int sum = arr[i] + arr[j];
// If X - sum is present in hash table,
if (mp.find(X - sum) != mp.end())
// Making sure that all elements are
// distinct array elements and an element
// is not considered more than once.
pair<int, int> p = mp[X - sum];
if (p.first != i && p.first != j &&
p.second != i && p.second != j)
cout << arr[i] << ", " << arr[j] << ", "
<< arr[p.first] << ", "
<< arr[p.second];
return;
// Driver program to test above function
int main()
int arr[] = 10, 20, 30, 40, 1, 2;
int n = sizeof(arr) / sizeof(arr[0]);
int X = 91;
findFourElements(arr, n, X);
return 0;
如何找到此代码失败的测试用例,或者如果正确,如何找到?
【问题讨论】:
如果数组是:[1 2 3 6 2 3] 并且总和是 12 那么你可以匹配对 (1,4) 和 (2,3) 或者你可以匹配 (1,4 ) 与 (5,6)。您可以使用数组 [(2,3) (5,6)] 存储键为 5 的哈希,但有什么意义呢?您只需要总和为 5 的一对,除非您试图找出总和为 12 的四个项目的所有组合。您只是想找到一个或所有组合吗? @JerryJeremiah 只是一种组合 好吧,这不是证据,但我认为他们是对的。如果数组中有重复的值,它们将存储最后一个值的索引,但是当搜索发生时,它们将与另一个匹配。我想不出它不起作用的情况。也许您需要在 math.stackexchange.com 上提问 ... Do not use#include <bits/stdc++.h>
和 avoid using namespace std;
。它们单独可能会造成问题,但它们一起可以变成灵魂的毁灭者和时间的浪费。
【参考方案1】:
算法是正确的。考虑满足以下条件的四元组(a, b, c, d)
: (1) arr[a] + arr[b] + arr[c] + arr[d] == k
; (2)a < b < c < d
.
很明显,当且仅当存在这样的四重 (a, b, c, d)
时,数组的四个不同元素之和为 k
。
现在考虑 (a, b)
对。您提到程序记录了最后一对(e, f)
(e < f
),它是(a, b)
(即arr[a] + arr[b] + arr[e] + arr[f] == k
) 的补充。请注意,由于(e, f)
是具有此类属性的最后一对,所以e >= c
。因此a < b < e < f
。现在我们找到了一个有效的四元组(a, b, e, f)
。
由于第二个循环遍历了所有对,所以必须已经访问了对 (a, b)
,并且必须检测到四元组。所以算法是正确的。
【讨论】:
【参考方案2】:它只存储最后一个总和的对。
不完全是。它存储 所有 对,就像您存储所有长度为 2 的数组一样。他们的算法在这里:
// Store sums of all pairs in a hash table
unordered_map<int, pair<int, int>> mp;
for (int i = 0; i < n-1; i++)
for (int j = i+1; j < n; j++)
mp[arr[i] + arr[j]] = i, j;
i, j
是由i
作为第一个值和j
作为第二个值组成的对。
我认为你对这里发生的事情感到困惑:
pair<int, int> p = mp[X - sum];
if (p.first != i && p.first != j &&
p.second != i && p.second != j)
他们正在从地图中拉出一对。值得注意的是,它们匹配以形成X
总和。他们可以做到:
if (mp[X - sum].first != i && mp[X - sum].first != j &&
mp[X - sum].second != i && mp[X - sum].second != j)
但这既丑陋又需要大量地图查找。因此,他们决定将他们关心的这对复制到一个局部变量 p
中。
然后他们确保p
中的两个索引都不是他们现在正在查看的索引i
和j
。这有意义吗?
【讨论】:
它如何存储所有的对,而 unordered_map 的值只是一对?存储所有对不应该是对的向量吗? @Gyan 我不清楚你在问什么。地图(无序或无序)是(key, value)
对的集合。这里的值是std::pair
,因此映射是映射和的集合,如sum -> (index1, index2)
。对向量可以工作,但它需要您执行 O(n^2) 循环以找到总和为您正在寻找的对(并在每次运行该循环时重新计算这些总和)。使用 unordered_map,查找的平均时间为 O(1),并且您已经得到了一次计算和存储的总和。
@scohe001 考虑mp[10] = 2,8
,后跟mp[10] = 3,7
。然后问自己,“mp[10]
的价值是什么?”关键是,即使代码在地图中“存储”了两对,也只保留了其中一对。保留的对是给定密钥的最后对。以上是关于在 4 sum 问题中查找代码失败的测试用例的主要内容,如果未能解决你的问题,请参考以下文章