一个向量中相加得到和S的值的数量。

huangapple go评论69阅读模式
英文:

Number of values in a vector that add up to a sum S

问题

我有以下任务:

编写具有以下函数头的函数:long long CountSumS(vector<int> &a, int s)

该函数将返回满足(a[i], a[j]);i < j; a[i] + a[j] = s的对数。
示例
如果a = (8, 2, 3, 8, 7, 5),s = 10,则该函数将返回3,这些对是(8, 2),(2, 8)和(3, 7)

我还尝试高效地解决这个问题,因此简单地获取每个其他元素并检查其后的所有值的总和并不是我正在寻找的解决方案。

我尝试使用无序多重映射解决此问题,并编写了以下函数:

long long CountSumS(vector&lt;int&gt;&amp; v, int sum)
{
    int cnt = 0;
    typedef unordered_multimap&lt;int, int&gt;::iterator iter;
    unordered_multimap&lt;int, int&gt; m;

    for (int i = 0; i &lt; v.size(); i++)
        m.insert(make_pair(v[i], i));

    for (int i = 0; i &lt; v.size(); i++)
    {
        int x = sum - v[i];
        // 使总和所需的值

        pair&lt;iter, iter&gt; result = m.equal_range(x);
        int count = distance(result.first, result.second);

        if (count != 0)
        {
            for (auto iter = result.first; iter != result.second; iter ++) // 遍历值
            {
                if (iter-&gt;second &gt; i)
                    cnt++;
                /*else
                    iter = m.erase(iter);*/
            }
        }
    }
    return cnt;
}

它以低效的方式解决了问题,因为最终只是检查具有特定键的所有元素,所以我考虑的解决方案是删除映射中所有值小于"i"的元素,因为这意味着该元素已经在向量中经过,并且无法用于形成总和。在/**/中写的部分是我尝试在迭代器处擦除该值的尝试,但当我尝试运行代码时出现错误(图像)(https://i.stack.imgur.com/Nl3SI.png)。我想知道是什么原因导致了该错误。

我感谢关于更简单解决方案的所有意见,这只是我能想到并尝试实施的第一件事。

英文:

I have the following task:

Write the function that has the header:long long CountSumS(vector<int> &a, int s)

The function will return the number of pairs with (a[i], a[j]); i < j; a[i] + a[j] = s)
Example:
If a = (8, 2, 3, 8, 7, 5) and s = 10, the function will return 3, the pairs being (8, 2), (2, 8) and (3, 7)

I'm also trying to do this efficiently, so simply taking every other element and checking the sum of all the values after it isn't the solution I'm looking for.

I tried solving this using an unordered multimap and I have the following function:

long long CountSumS(vector&lt;int&gt;&amp; v, int sum)
{
    int cnt = 0;
    typedef unordered_multimap&lt;int, int&gt;::iterator iter;
    unordered_multimap&lt;int, int&gt; m;

    for (int i = 0; i &lt; v.size(); i++)
        m.insert(make_pair(v[i], i));

    for (int i = 0; i &lt; v.size(); i++)
    {
        int x = sum - v[i];
        //the needed value to make the sum

        pair&lt;iter, iter&gt; result = m.equal_range(x);
        int count = distance(result.first, result.second);

        if (count != 0)
        {
            for (auto iter = result.first; iter != result.second; iter ++) //iterates through the values 
            {
                if (iter-&gt;second &gt; i)
                    cnt++;
                /*else
                    iter = m.erase(iter);*/
            }
        }
    }
    return cnt;

It solves the problem inefficiently because after all it just checks through all elements with a certain key, so the solution I thought of was to delete all elements in the map that have value smaller than "i", since it means the element has already been passed in the vector and I can't use it to form a sum anyway. The section written in the /**/ was my approach at trying to erase the value at that iterator, but I get an error when I tried to run the code (image)(https://i.stack.imgur.com/Nl3SI.png). I was wondering what was causing that error.

I appreciate all input on a better aproach for an easier solution, it was just the first thing I could think of and tried to implement.

答案1

得分: 0

使用iter = m.erase(iter)之后再使用iter++可能会导致迭代器越界。在每次迭代中只执行其中一个操作。

            for (auto iter = result.first; iter != result.second; ) //遍历值
            {
                if (iter->second > i)
                {
                    cnt++;
                    iter++;
                }
                else
                    iter = m.erase(iter);
            }
英文:

Using iter ++ after iter = m.erase(iter) may result in an iterator overrun.

Do only one of them in each iteration.

            for (auto iter = result.first; iter != result.second; ) //iterates through the values 
            {
                if (iter-&gt;second &gt; i)
                {
                    cnt++;
                    iter++;
                }
                else
                    iter = m.erase(iter);
            }

答案2

得分: 0

不要回答我要翻译的问题。以下是已翻译的内容:

如果你只想返回满足 (a[i], a[j]); i &lt; j; a[i] + a[j] = s 条件的配对数,你可以使用不同的方法。

不要创建一个 std::unordered_multimap&lt;int,int&gt; 容器,它是一个哈希表,然后将所有元素的配对插入其中再检查满足条件的配对,你应该使用另一个排序后的 std::vector&lt;int&gt; 容器。这样,如果你有一个元素 a[i],你需要找到满足等式 a[i] + a[j] = s 的另一个元素 a[j],其中 i &lt; j,你可以在容器范围内迭代。

关于效率,我建议你进行以下优化:使用复制构造函数将元素从给定的向量传输到你的向量,这样可以避免将来的重新分配,并使你的代码更清晰;使用标准算法,即 std::sort() 对向量进行排序。

因此,你可以利用二分搜索算法来找到每个元素 a[i]的元素数量,因此总和不会超出给定范围。

算法如下。
初始化变量,比如将 right 设置为 a.size() – 1count 设置为 0,用于存储总和在范围[L, U]上的配对数。迭代直到 right 大于0,并找到与 a[right] 总和大于或等于 L 的元素的起始索引。然后,找到与 a[right] 总和小于或等于 U 的元素的结束索引。如果结束大于或等于开始,那么将 (end – start + 1) 添加到表示当前元素的总和在范围[L, U]上的元素数的计数中,然后递减 right

此外,你应该进行一些小的修正,但不重要的错误:函数参数 std::vector&lt;int&gt;&amp; 应该是一个常量引用 const std::vector&lt;int&gt;&amp;,因为它包含的元素永远不会被修改。

英文:

If you want only to return the number of pairs with (a[i], a[j]); i &lt; j; a[i] + a[j] = s, you could use a different approach.

Instead of creating a std::unordered_multimap&lt;int,int&gt; container, that is a hash table, and insert all the pairs of the elements into it before checking the pairs that satisfy your predicate, you should use another std::vector&lt;int&gt; container, which elements are sorted. Thus, if you have an element a[i] and you need to find some other element a[j], with i &lt; j, that satisfy the equivalence a[i] + a[j] = s, you will iterate through the container in the range.

About the efficiency, I can advice you to do the following optimizations: transfer the elements from the given vector to your vector using a copy ctor, so you avoid future reallocations and your code is clearer; sort the vector using a standard algorithm, i.e. std::sort().

So, you can take advantage of a binary search algorithm to find the number of elements for each element a[i] therefore the sum will not exceed the given range.

The algorithm is the following.
Initialize variables say, right as a.size() – 1 and count as 0 to store numbers of pairs whose sum lies over the range [L, U]. Iterate until the right is greater than 0, and find the starting index of the element whose sum with a[right] is greater than or equal to L. Then, find the ending index of the element before a[right] whose sum with a[right] is less than or equal to U. If the end is greater than equal to the start, then add (end – start + 1) to the count representing the number of elements whose sum with the current element lies over the range [L, U] and then decrement right.

Furthermore, you should correct a little, but not important, error: the function argument std::vector&lt;int&gt;&amp; should be a constant reference const std::vector&lt;int&gt;&amp;, since the elements it contains are never modified.

huangapple
  • 本文由 发表于 2023年3月3日 22:10:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75628143.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定