如果满足所需的时间复杂度,为啥我的代码会超时?

Posted

技术标签:

【中文标题】如果满足所需的时间复杂度,为啥我的代码会超时?【英文标题】:Why did my code timed out if required time complexity is met?如果满足所需的时间复杂度,为什么我的代码会超时? 【发布时间】:2021-03-14 11:14:52 【问题描述】:

我尝试解决 CodeWars kata 并遇到超时错误。我在 cmets 中读到代码应该是 O(n) 复杂度。虽然,我的代码实际上是 O(n)。所以,也许我犯了一些错误等等。为什么这不起作用?有人应该解释为什么我的代码比 O(n) 慢吗?

#include <string>
using namespace std;

bool scramble(const std::string& s1, const std::string& s2)

    string copy = s1;
    int sum = 0;
    for (int i=0; i < s2.size(); ++i)
    
        size_t found = copy.find(string(1,s2[i]));
        if (found != string::npos)
        
            sum++;
            copy.erase(found,1);
        
    
    if (sum == s2.size())return true;
    return false;


【问题讨论】:

erasefind 通常具有线性时间复杂度。所以你的复杂性在 O(s1.length()*s2.length()) 虽然,我的代码实际上是 O(n)。 -- 不是O(n)。如果 string 是 1000 个字符,而您在第一个字符上调用 erase 怎么办?被擦除字符前面的所有字符都必须上移一位。如果您使用不同的数据结构,例如std::list&lt;char&gt;,也许您可​​以声明O(n) @PaulMcKenzie 感谢您的建议。我会想办法的。 @kirillshvedov -- 什么是“CodeWars kata”?您要解决的问题是什么? 【参考方案1】:

我看到的最大问题是copy.find()copy.erase() 比你想象的要贵。它们本质上是 O(n),并且由于它处于 O(n) for 循环中,因此您至少有 O(n^2) 的运行时间。

通过计算字母,您可以完全避免这种情况。下面的代码是 O(3n) --> O(n)。它还通过了所有测试。

#include<string>
#include <array>

bool scramble(const std::string& s1, const std::string& s2)
  std::array<int, 26> s1LetterCounts0;
  for (auto& i : s1) 
    ++s1LetterCounts[i - 'a'];
  
  
  for (auto& i : s2) 
    --s1LetterCounts[i - 'a'];
  
  
  for (auto& i : s1LetterCounts) 
    if (i < 0) 
      return false;
    
  
  
  return true;

最后的 if 条件是满足子串要求。 s1 可能包含 s2 不包含的字符,因此 s2 从计数数组中递减的循环可能会留下一些正数,但绝不应该留下负数。

我可能会在性能方面做得更多(合并第 2 和第 3 个循环),但它按原样通过。

【讨论】:

以上是关于如果满足所需的时间复杂度,为啥我的代码会超时?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的编译器保留的空间比函数堆栈帧所需的空间多?

为啥我的 ArrayList 没有打印出 Java 所需的输出?

如何减少 Wildfly 部署所需的时间?

为啥云构建说我缺少我的项目所需的“compute.instances.create”权限?

为啥这个选择排序代码在 Cpp 中,没有给出所需的输出

为啥要执行权限以及在 c(Linux) 中创建文件所需的写权限? [关闭]