【问题标题】:Most efficient algorithm for Two-sum problem (involving indices)二和问题的最有效算法(涉及索引)
【发布时间】:2021-12-09 15:49:11
【问题描述】:

问题陈述给定一个数组和一个给定的总和“T”,找到数组中元素的所有索引对,加起来为 T。附加要求/约束​​:

  • 索引从 0 开始
  • 索引必须首先显示较低的索引(例如:24、30 而不是 30、24)
  • 索引必须按升序显示(例如:如果我们找到 (1,3)、(0,2) 和 (5,8),则输出必须是 (0,2) (1,3) (5 ,8)
  • 数组中可能存在重复元素,这也是必须考虑的

这是我的 C++ 代码,我使用了 unordered_set 的哈希表方法:

void Twosum(vector <int> res, int T){
    
    int temp; int ti = -1;
    unordered_set<int> s;
    vector <int> res2 = res;                  //Just a copy of the input vector
    vector <tuple<int, int>> indices;         //Result to be output
    
    for (int i = 0; i < (int)res.size(); i++){
        temp = T - res[i];

        if (s.find(temp) != s.end()){
            
            while(ti < (int)res.size()){     //While loop for finding all the instances of temp in the array, 
                                             //not part of the original hash-table algorithm, something I added
                
                ti = find(res2.begin(), res2.end(), temp) - res2.begin();  
                                              //Here find() takes O(n) time which is an issue
                
                res2[ti] = lim;               //To remove that instance of temp so that new instances 
                                              //can be found in the while loop, here lim = 10^9
                
                if(i <= ti) indices.push_back(make_tuple(i, ti));
                else indices.push_back(make_tuple(ti, i)); 
            }
        }
        s.insert(res[i]);
    }
    
    if(ti == -1)
        {cout<<"-1 -1";                        //if no indices were found
         return;}
    
    sort(indices.begin(), indices.end());       //sorting since unordered_set stores elements randomly
    for(int i=0; i<(int)indices.size(); i++)
        cout<<get<0>(indices[i])<<" "<<get<1>(indices[i])<<endl;
}

这有多个问题:

  • 首先,while 循环没有按预期工作,而是显示SIGABRT 错误(free(): invalid pointer)。 ti 索引也以某种方式超出了向量范围,即使我在 while 循环中进行了检查。
  • 其次,find() 函数在 O(n) 时间内工作,这将整体复杂度增加到 O(n^2),这导致我的程序在执行期间超时。然而,这个函数是必需的,因为我们必须输出索引。
  • 最后,当数组中有许多重复元素时,unordered-set 实现似乎不起作用(因为集合只采用唯一元素),这是问题的主要限制之一。这让我觉得我们需要某种哈希函数或哈希图来处理重复项?我不确定...

我在互联网上找到的所有不同算法都只处理打印元素而不是索引,因此我没有解决这个问题。

如果你们中的任何人知道一个最佳算法,同时满足约束并在 O(n) 时间下运行,我们将非常感谢您的帮助。提前谢谢你。

【问题讨论】:

  • 您的算法无法在O(n) 时间内运行。如果您的数组中填充了1s 和T=2,那么将有O(n²) 对满足您的要求的索引。因此,您的输出大小可能为O(n²)。至于在小于O(n) 的情况下运行,那就更难了,因为在数组中简单查找元素需要O(n) 操作。
  • @m.raynal 我知道,这就是为什么我要问是否有更好的优化算法来解决这个问题,它适用于索引。
  • 理论上(大O复杂度),这是同样的问题。在实践中,您可以开始构建一个映射,其中键是元素,值是与该元素对应的索引集。然后,您可以应用适用于元素的算法,并迭代相应索引的所有组合。如果阵列中有很多冗余,它应该在实践中带来不错的加速。如果这是你要找的,我可以用这个算法写一个答案
  • @m.raynal 是的,这可能只是工作,是的,请您的完整答案真的很有帮助????????

标签: c++ algorithm vector hashtable sigabrt


【解决方案1】:

这是一个使用哈希表(或映射)和集合回答您问题的伪代码。我让您使用经过调整的数据结构将其转换为 cpp(在这种情况下,经典的哈希图和集合可以很好地完成这项工作)。

符号:我们将A 表示数组,n 表示它的长度,T 表示“总和”。

// first we build a map element -> {set of indices corresponding to this element}
Let M be an empty map; // or hash map, or hash table, or dictionary
for i from 0 to n-1 do {
    Let e = A[i];
    if e is not a key of M then {
        M[e] = new_set()
    }
    M[e].add(i)
}

// Now we iterate over the elements
for each key e of M do {
    if T-e is a key of M then {
        display_combinations(M[e], M[T-e]);
    }
}

// The helper function display_combinations
function display_combinations(set1, set2) {
    for each element e1 of set1 do {
        for element e2 of set2 do {
            if e1 < e2 then {
                display "(e1, e2)";
            } else if e1 > e2 then {
                display "(e2, e1)";
            }
        }
    }
}

正如 cmets 中所说,该算法在最坏情况下的复杂度为O(n²)。看到我们不能低于这种复杂性的一种方法是,在数组的所有元素都具有值T/2 的情况下,输出的大小可能在O(n²)

编辑:此伪代码不按顺序输出对。只需将它们存储在一对数组中,并在显示之前对该数组进行排序。同样,我没有处理一对(i, i) 可以满足要求的情况。您可能需要考虑它(只需在最后一个循环中将e1 &gt; e2 更改为e1 &gt;= e2

【讨论】:

  • 感谢您的回答。我在 C++ 中使用地图尝试过这个,但是如果数组中有很多重复项,它就不起作用。我忘了在问题本身中提到这一点:这个问题有点强调处理重复项,这让我认为我们需要某种形式的散列或散列函数......
  • 您需要一个将整数映射到集合的映射。类似std::map &lt;int, std::set&gt;.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-22
  • 1970-01-01
  • 2020-09-30
  • 1970-01-01
  • 2014-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多