字符串相乘的有效方法

Efficient way to multiply string

本文关键字:有效 方法 字符串      更新时间:2023-10-16

http://ideone.com/g7rGS7

正如你所看到的,它超过了时间限制。

有人给了我一个想法,让10个左右的静态变量为空,并将它们连接起来形成更大的空间,所以我想尝试通过2的幂来实现。代码可以工作,但显然非常慢。做这件事有什么更快的方法?

std::string operator*(std::string const &s, size_t n)
{
    std::string r;
    r.reserve(n * s.size());
    for (size_t i=0; i<n; i++)
        r += s;
    return r;
}
std::string operator^(std::string const &s, size_t n)
{
    std::string r = s;
    for (size_t i = 1; i < n; i++)
    {
        r = s * r.size();
    }
    if (n == 0) return std::string(" ");
    return r;
}
int main()
{
    string blank = " ";
    string blank2 = blank * 2;
    string blank4 = blank2 ^ 2;
    string blank8 = blank2 ^ 3;
    string blank16 = blank2 ^ 4;
    for (int i = 0; i < 100; i++)
        assert((blank2 ^ i).size() == pow(2, i));
    return 0;
}

如本评论中所述,您可以执行以下操作:

std::string str_double (std::string const & s)
{
    return s + s;
}
std::string operator*(std::string const &s, size_t n)
{
    return str_double(s * (n / 2)) + ((n % 2) ? s : std::string());
}

我相信,如果您的编译器和标准库支持右值引用和移动,这是非常有效的。

然而,我不认为任何东西会比简单的版本快得多,比如:

std::string operator*(std::string const &s, size_t n)
{
    std::string r;
    r.resize (n * s.size()); // note resizing, not reserving
    for (size_t i = 0, j = 0; i < n; ++i, j += s.size())
        memcpy (&(r[j]), &(s[0]), s.size());
    return r;                
}

您的运算符^执行大量字符串分配。运算符*预先分配字符串,这很好,但您的运算符^每次调用运算符*时都会创建一个中间字符串。相反,预先计算r的长度和所需的副本数。然后,您可以预分配r并执行连接,而无需创建一堆不需要的字符串。

如果您想用1个字符(示例中的空格)填充它,那么让它们更快的方法是完全消除for循环:

int main()
{
    string blank2(2, ' ');
    string blank4(4, ' ');
    string blank8(8, ' ');
    string blank16(16, ' ');
    // etc
    return 0;
}

为了使它通用(这样你就可以用不止一个字符来完成),你仍然需要限制你的循环:

std::string operator*(std::string const &s, size_t n)
{
    std::string r(n * s.size(), ' '); // initialize the string with the needed size
    for (size_t i=0; i<n; i++) // O(n)
        r += s;
    return r;
}
std::string operator^(std::string const &s, size_t n)
{
    size_t sn = std::pow(s.size(), n);
    std::string r(sn, ' ');
    for (size_t i = 1; i < sn; i++) // since this doesn't have an inner loop in the * operator, it is O(n) instead of O(n^2)
    {
        r += s;
    }
    return r;
}
int main()
{
    string blank = " ";
    string blank2 = blank * 2;
    string blank4 = blank2 ^ 2;
    string blank8 = blank2 ^ 3;
    string blank16 = blank2 ^ 4;
    for (int i = 0; i < 100; i++)
        assert((blank2 ^ i).size() == pow(2, i));
    return 0;
}