【问题标题】:C++ How to optimize this algorithm ? (std::map)C++如何优化这个算法? (标准::地图)
【发布时间】:2021-10-10 10:33:07
【问题描述】:

问题如下:给定一个数字's',s ∈ [0, 10^6],和一个数字'n',n ∈ [0, 50000],然后是n个数字,我们有找出有多少个数对的总和等于 's' 数(我们必须使用映射或集合来解决它)

示例如下:

输入:

5 (this is s)
6 (this is n)
1 
4 
3 
6 
-1 
5 

输出:

2

解释:这些是 (1,4) 和 (6,−1) 对。 (1 +4 = 5 和 6 + (-1) = 5)

这是我的“解决方案”,我什至不知道它是否正确,但它适用于我们得到的示例。

#include <iostream>
#include <map>
#include <iterator>
using namespace std;

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    int s;
    cin >> s;
    int n;
    cin >> n;
    map<int, int> numbers;

    int element;
    int counter = 0;
    for(int i=0; i<n;i++)
    {
        cin >> element;
        numbers.insert(pair<int, int>(element, s-element));

    }
    for(map<int, int>::iterator it = numbers.begin(); it != numbers.end(); it++)
    {
        map<int, int>::iterator it2 = it;
        while(it2 != numbers.end())
        {
            if(it->second == it2->first)
            {
                counter++;
                break;
            }
            it2++;

        }
    }
    cout << counter << "\n";
    return 0;
}

提前感谢您的回答!我还是个初学者,正在学习中,抱歉。

【问题讨论】:

  • 忘了补充:允许的最长时间为0.11秒,我的解决方案比我在测试站点上运行时慢。那么,如果解决它的方法是正确的,我怎样才能让它更快更高效呢?
  • 也许可以试试std::unordered_map,它有平均O(1) 查找——它是一个哈希映射。以后也可以随时编辑您自己的问题以添加更多信息。
  • 没关系,第二个 for 循环是 O(n^2) 并且完全没有必要,您可以只检查 element, s-element 的存在而不是插入。
  • 使用std::map::find 代替内部循环。当你用没有重复的输入来确定它时,想想你将如何处理重复。
  • @Quimby 这样我就可以完全删除第二个 for 循环和 while 循环,只使用第一个 for 循环来解决它?

标签: c++ c++14


【解决方案1】:

element, s-element 是个好主意,但没有理由存储所有对,然后才检查重复项。这将删除最后的O(n^2) 循环。

使用散列的标准方法是:

seen=unordered_map<number,count>() 
for 1...n:
  e = read_int()
  if (s-e) in seen:
    duplicates+=seen[s-e] # Found new seen[s-e] duplicates.
  if e in seen:
    seen[e]+=1
  else:
    seen.insert(e,1)

return duplicates

【讨论】:

    【解决方案2】:

    这是一种蛮力方法,使用向量:

    int target_s = 0;
    int quantity_numbers = 0;
    std::cin >> target_s >> quantity_numbers;
    std::vector<int> data(quantity_numbers);
    for (int i = 0; i < quantity_numbers; ++i)
    {
        cin >> data[i];
    }
    
    int count = 0;
    for (int i = 0; i < quantity_numbers; ++i)
    {
        for (j = 0; j < quantity_numbers; ++j)
        {
            if (i == j) continue;
            int pair_sum = data[i] + data[j];
            if (pair_sum == target_s) ++count;
        }
    }
    std::cout << count;
    

    上面的代码包含了pair == s和pair == s的情况。在这种情况下,不确定要求是否只需要对

    【讨论】:

      【解决方案3】:

      与此类问题一样,选择适当的算法将改善您的解决方案。编写一些“更好”的 C++ 代码几乎无济于事。此外,对于这种算法,暴力破解几乎从来都不是解决方案。

      使用下面描述的方法(当然不是我发明的),我们只需要一个std::map(或者更好的是std::unordered_map)和一个for循环。我们不需要将读取的值存储在额外的std::vector 或类似的地方。因此,我们可以提出低内存消耗和快速计算。

      方法。任何时候,在读取一个值后,我们都会根据所需的总和计算 delta。

      如果我们看一下当前值和一些先前读取的值相加的要求条件,应该加起来所需的总和,我们可以写出以下数学方程:

      currentValue + previouslyReadValue = desiredSum 
         or
      desiredSum - currentValue =  previouslyReadValue
         or with
      delta = desiredSum - currentValue
         -->
      delta == previouslyReadValue
      

      因此,我们需要查看已读取的值,如果它们等于 delta(因为它们会将所需的总和相加),将它们的出现计数相加得到有效对的计数。

      已读取的值及其出现次数将存储在 std::unordered_map 中。

      所有这些都将产生一个 10 行的解决方案:

      #include <iostream>
      #include <unordered_map>
      
      int main() {
          // Initialize our working variables
          int numberOfValues{}, desiredSum{}, currentValue{}, resultingCount{};
      
          // Read basic parameters. Desired sum and overall number of input values.
          std::cin >> desiredSum >> numberOfValues;
      
          // Here, we will store all values and their count of occurence
          std::unordered_map<int, int> valuesAndCount{};
      
          // Read all values and operate on them
          for (int i{}; i < numberOfValues; ++i) {
      
              std::cin >> currentValue;                       // Read from cin
              const int delta{ desiredSum - currentValue };   // Calculate the delta from the desired sum
      
              // Look, if the calculated delta is already in the map. Becuase, if the delta and the
              // current value sum up to our desired sum, then we found a valid pair.
              if (valuesAndCount.find(delta) != valuesAndCount.end())
      
                  // Increase the resulting count, by the number of times that this delta value has already been there
                  resultingCount += valuesAndCount[delta];
      
              // Nothing special, Just cound the occurence of this value.
              valuesAndCount[currentValue]++;
          }
          return !!(std::cout << resultingCount);
      }
      

      【讨论】:

        猜你喜欢
        • 2011-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-18
        • 2013-05-13
        • 1970-01-01
        • 2014-02-11
        相关资源
        最近更新 更多