在 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 &lt;bits/stdc++.h&gt; 和 avoid using namespace std;。它们单独可能会造成问题,但它们一起可以变成灵魂的毁灭者和时间的浪费。 【参考方案1】:

算法是正确的。考虑满足以下条件的四元组(a, b, c, d): (1) arr[a] + arr[b] + arr[c] + arr[d] == k; (2)a &lt; b &lt; c &lt; d.

很明显,当且仅当存在这样的四重 (a, b, c, d) 时,数组的四个不同元素之和为 k

现在考虑 (a, b) 对。您提到程序记录了最后一对(e, f) (e &lt; f),它是(a, b) (即arr[a] + arr[b] + arr[e] + arr[f] == k) 的补充。请注意,由于(e, f) 是具有此类属性的最后一对,所以e &gt;= c。因此a &lt; b &lt; e &lt; 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 中的两个索引都不是他们现在正在查看的索引ij。这有意义吗?

【讨论】:

它如何存储所有的对,而 unordered_map 的值只是一对?存储所有对不应该是对的向量吗? @Gyan 我不清楚你在问什么。地图(无序或无序)是(key, value) 对的集合。这里的值是std::pair,因此映射是映射和的集合,如sum -&gt; (index1, index2)。对向量可以工作,但它需要您执行 O(n^2) 循环以找到总和为您正在寻找的对(并在每次运行该循环时重新计算这些总和)。使用 unordered_map,查找的平均时间为 O(1),并且您已经得到了一次计算和存储的总和。 @scohe001 考虑mp[10] = 2,8,后跟mp[10] = 3,7。然后问自己,“mp[10] 的价值是什么?”关键是,即使代码在地图中“存储”了两对,也只保留了其中一对。保留的对是给定密钥的最后对。

以上是关于在 4 sum 问题中查找代码失败的测试用例的主要内容,如果未能解决你的问题,请参考以下文章

相同的测试用例显示不同的答案

在UI自动化测试中使用flaky插件运行失败用例

Django 3.0.8 测试用例失败

量角器中的测试失败会停止执行休息测试用例

如果机器人框架中的第一个测试用例失败,如何跳过测试用例执行

Python接口测试实战4(下) - 框架完善:用例基类,用例标签,重新运行上次失败用例