【问题标题】:How do I return all possible triplets in the 3Sum problem?如何在 3Sum 问题中返回所有可能的三元组?
【发布时间】:2022-06-17 14:48:55
【问题描述】:

我正在做 3Sum 问题:https://leetcode.com/explore/interview/card/top-interview-questions-medium/103/array-and-strings/776/

简单问题:给定一个整数数组 nums,返回所有三元组 [nums[i], nums[j], nums[k]],使得 i != ji != kj != knums[i] + nums[j] + nums[k] == 0。 请注意,解集不得包含重复的三元组。

我的问题:我有一个解决方案,它确实返回了一些但不是所有可能的三元组,我不明白我哪里出错了。其次,我的算法是O(N^2 log N),欢迎提出改进建议。

Input:
[-1,0,1,2,-1,-4,-2,-3,3,0,4]
Output:
[[-3,-1,4],[-3,0,3],[-4,1,3],[-2,0,2],[-4,0,4]]
Expected:
[[-4,0,4],[-4,1,3],[-3,-1,4],[-3,0,3],[-3,1,2],[-2,-1,3],[-2,0,2],[-1,-1,2],[-1,0,1]]

算法:我已经将我的算法与 cmets 一起包含在代码中,但这里是要点 - 对于每对数字,我将它们的 sum 存储为 key 以及给我的数字的索引 @ 987654330@ 作为value。然后在一个循环中,我遍历每个元素并检查target 值与该数字之间的差异是否以key 的形式出现在map 中。如果是,并且所有索引都不相等,我将其添加到最终返回的 vector

代码:

#include <iostream>
#include <vector>
#include <unordered_map>

using namespace std;

vector<vector<int>> threeSum(vector<int> &nums) {
    /*
     * If less than 3 elements are passed return empty vector
     */
    if (nums.size() < 3)
        return {};

    int target = 0; // all three numbers sum up to 0 as given
    vector<vector<int>> outer; // this is returned by the function
    unordered_map<int, vector<int>> umap; // unordered_map for keeping sum and indices

    /*
     * Calculate sum of each pair of numbers
     * Store the sum as key and the pair as value
     * i != j is guaranteed
     */
    for (int i = 0; i < nums.size(); i++)
        for (int j = i + 1; j < nums.size(); j++)
            umap[nums[i] + nums[j]] = {i, j};

    /*
     * Go through each element and calculate the difference
     * between target and that element, this gives the sum
     * of the other two elements.
     * Look for the sum in unordered_map
     * If it is present check if all three indices are not equal to each other
     */
    for (int i = 0; i < nums.size(); i++) {
        vector<int> inner;
        int diff = target - nums[i];
        auto it = umap.find(diff);
        inner = umap[diff];
        if (it != umap.end() && i != inner[0] && i != inner[1]) {
            inner.push_back(i);
            vector<int> tmp;
            for (auto &j: inner)
                tmp.push_back(nums[j]); // push actual numbers instead of indices
            sort(tmp.begin(), tmp.end()); // sort the inner three elements
            if (find(outer.begin(), outer.end(), tmp) == outer.end()) // for removing duplicates
                outer.push_back(tmp);
        }
    }
    return outer;
}

int main() {
    vector<int> v{-1, 0, 1, 2, -1, -4, -2, -3, 3, 0, 4};
    vector<vector<int>> ret = threeSum(v);
    for (auto &i: ret) {
        for (auto j: i)
            cout << j << " ";
        cout << endl;
    }
}

【问题讨论】:

  • 我已将我的算法包含在代码中 -- 不,您编写了一个您认为遵循您的算法的程序。回到我的第一条评论——如果你的算法是正确的,那么你的代码可能没有遵循它,是时候调试你的代码,看看它从你的算法转移到哪里了。

标签: c++ algorithm data-structures


【解决方案1】:

您的错误通过输入 [-5, 1, 2, 3, 4] 进行演示。

问题是5 == 1+4 == 2+3。您的 map 只会将其中一对存储为该键的值,因此它不会记录这两个对都可以导致该键的事实。

【讨论】:

    【解决方案2】:

    既然你要求改进这个算法怎么样:

    创建一个std::unordered_map&lt;int, int&gt; 将每个输入映射到出现次数。那么:

    for (const auto & it = map.begin(); it != map.end(); ++it) {
        for (const auto & it2 = it; it2 != map.end(); ++it2) {
            auto it3 = map.find(-*it - *it2);
            if (it3 != map.end()) {
                it ((*it > *it3) || (*it2 > *it3)) continue;
                if (it == it2) {
                    if (it == it3) {
                       if (it.second > 2) cout << *it << ", " *it2 << ", " << *it3 << std::endl;
                    } else {
                       if (it.second > 1) cout << *it << ", " *it2 << ", " << *it3 << std::endl;
                    }
                } else if (it2 == it3) {
                    if (it2.second > 1) cout << *it << ", " *it2 << ", " << *it3 << std::endl;
                } else {
                    cout << *it << ", " *it2 << ", " << *it3 << std::endl;
                }
            }             
        }
    }
    

    应该是O(n^2),没有重复。

    【讨论】:

    • 我想知道我的算法是否真的是O(N^2 log N),因为我正在做的排序步骤sort(tmp.begin(), tmp.end()); // sort the inner three elements实际上每次只是对3个元素进行排序(“三元组”),所以因为它没有缩放有了输入,它应该仍然是O(N^2)。我可以简单地使用几个if-else 语句来代替,这样就可以避免调用sort()
    • @DivyanshuVarma 如果您的算法完全错误,这有什么帮助?
    • 我不是在谈论对与错,只是我最初忽略了一些事情。顺便说一句,如果您能用文字解释您的方法,那将会很有帮助。
    • 它构建所有三元组,总和为0,每个数字出现的频率并不比输入中的频率高,其中it &lt;= it2*it3 是最大的以避免任何重复。跨度>
    • it ((*it &gt; *it3) || (*it2 &gt; *it3)) continue; 我想你的意思是if
    【解决方案3】:

    我确实解决了这个问题,但它效率低下,并且在一些测试用例上超出了时间限制。

    #include <iostream>
    #include <vector>
    #include <unordered_map>
    #include <set>
    
    using namespace std;
    
    vector<vector<int>> threeSum(vector<int> &nums) {
        /*
         * If less than 3 elements are passed return empty vector
         */
        if (nums.size() < 3)
            return {};
    
        int target = 0; // all three numbers sum up to 0 as given
        vector<vector<int>> outer; // this is returned by the function
        unordered_multimap<int, vector<int>> umap; // unordered_map for keeping sum and indices
    
        /*
         * Calculate sum of each pair of numbers
         * Store the sum as key and the pair as value
         * i != j is guaranteed
         */
        for (int i = 0; i < nums.size(); i++)
            for (int j = i + 1; j < nums.size(); j++) {
                vector<int> temp;
                temp.push_back(i);
                temp.push_back(j);
                umap.emplace(make_pair(nums[i] + nums[j], temp));
            }
    
        /*
         * Go through each element and calculate the difference
         * between target and that element, this gives the sum
         * of the other two elements.
         * Look for the sum in unordered_map
         * If it is present check if all three indices are not equal to each other
         */
        //unordered_set<vector<int>> uset;
        for (int i = 0; i < nums.size(); i++) {
            vector<int> inner;
            int diff = target - nums[i];
            auto it = umap.find(diff);
            while (it != umap.end()) {
                inner = it->second;
                if (it != umap.end() && i != inner[0] && i != inner[1]) {
                    inner.push_back(i);
                    //vector<int> tmp;
                    //for (auto &j: inner)
                    //    tmp.push_back(nums[j]); // push actual numbers instead of indices
                    //sort(tmp.begin(), tmp.end()); // sort the inner three elements
                    //if (find(outer.begin(), outer.end(), tmp) == outer.end()) // for removing duplicates
                    outer.push_back(inner);
    
                }
                umap.erase(it);
                it = umap.find(diff);
            }
        }
        for (auto &i: outer)
            for (auto &j: i)
                j = nums[j];
        //sort(i.begin(),i.end());
        set<vector<int>> uset;
        for (auto &i: outer) {
            sort(i.begin(), i.end());
            uset.insert(i);
        }
        outer.clear();
        outer.insert(outer.end(), uset.begin(), uset.end());
        return outer;
    }
    
    int main() {
        vector<int> v{-1, 0, 1, 2, -1, -4, -2, -3, 3, 0, 4};
        vector<vector<int>> ret = threeSum(v);
        for (auto &i: ret) {
            for (auto j: i)
                cout << j << " ";
            cout << endl;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      • 2018-07-29
      • 1970-01-01
      • 2014-02-07
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      相关资源
      最近更新 更多