我有一个小问题。我正在解决一个编程任务,但是遇到了问题。这很简单,但是时间限制会让它变得更难。
查找子字符串的出现次数。你将获得M - 长度 子串;要查找的子字符串,N - 基本字符串的长度;基础 字符串。
M <= 100 000
N <= 200 000输入
10
budsvabbud
79个
uaahskuskamikrofonu的 budsvabbud nebudlabutkspkspkspmusimriesit的 budsvabbudsvabbud NEL输出
3
我尝试使用内置函数find,但它不够快:
#include<iostream>
#include<string>
using namespace std;
int main()
{
int n;
int occurrences = 0;
string::size_type start = 0;
string base_string, to_find;
cin >> n >> to_find >> n >> base_string;
while ((start = base_string.find(to_find, start)) != string::npos) {
++occurrences;
start++;; // see the note
}
cout << occurrences << endl;
}
所以我尝试编写自己的函数,但速度更慢了:
#include<iostream>
#include<cstdio>
#include<string>
#include<queue>
using namespace std;
int main()
{
int n, m;
string to_find;
queue<int> rada;
int occurrences = 0;
cin >> m >> to_find >> n;
for (int i = 0; i < n; i++)
{
char c;
scanf(" %c", &c);
int max = rada.size();
for (int j = 0; j < max; j++)
{
int index = rada.front();
rada.pop();
if (c == to_find[index])
{
if (++index == m) {
occurrences++;
}
else
rada.push(index);
}
}
if (c == to_find[0])
{
if (1 == m)
n++;
else
rada.push(1);
}
}
cout << occurrences << endl;
}
我知道有些人在0毫秒内完成了这项工作,但我的第一个代码需要超过2000毫秒而第二个代码需要的时间远远超过2000毫秒。你有什么想法如何解决这个问题? 感谢。
编辑: 长度限制:
M&lt; = 100 000 - 子串的长度
N <= 200 000 - 基本字符串的长度
答案 0 :(得分:2)
您提供的算法是O(M * N),其中N是文本的长度,M是搜索世界的长度。通常,库也实现了朴素算法。然而,Knuth,Morrison和Pratt有一种算法,它在O(M + N)时间内完成。参见,例如,维基百科Knuth-Morrison-Pratt Algorithm。它有一些变体,可能更容易实现,如Boyer-Moore-Horsepool。
答案 1 :(得分:1)
static size_t findOccurences(const char * const aInput, const char * const aDelim)
{
if (aInput == 0x0 || aDelim == 0x0)
{
throw std::runtime_error("Argument(s) null");
}
const size_t inputLength = strlen(aInput);
const size_t delimLength = strlen(aDelim);
size_t result = 0;
if (delimLength <= inputLength && delimLength > 0)
{
size_t delimIndex = 0;
for (size_t inputIndex = 0; inputIndex < inputLength; inputIndex++)
{
if (aInput[inputIndex] != aDelim[delimIndex])
{
delimIndex = 0;
}
else
{
delimIndex++;
if (delimIndex == delimLength)
{
delimIndex = 0;
result++;
}
}
}
}
return result;
}
static size_t unsafeFindOccurences(const char * const aInput, const char * const aDelim)
{
const size_t inputLength = strlen(aInput);
const size_t delimLength = strlen(aDelim);
size_t result = 0;
size_t delimIndex = 0;
for (size_t inputIndex = 0; inputIndex < inputLength; inputIndex++)
{
if (aInput[inputIndex] != aDelim[delimIndex])
{
delimIndex = 0;
}
else
{
delimIndex++;
if (delimIndex == delimLength)
{
delimIndex = 0;
result++;
}
}
}
return result;
}
x86 x64
Debug 5501ms 5813ms
Release 3889ms 3998ms
x86 x64
Debug 5442ms 5564ms
Release 3074ms 3139ms
使用Windows 10 x64 Pro下的Visual Studio 2015,Visual Studio 2015(v140)工具集编译。
使用this输入。搜索“广告”和1.000.000次迭代。
答案 2 :(得分:0)
我在调试模式下尝试此代码而没有任何优化,并且 11毫秒。 VS.NET 2013,英特尔酷睿i7:
int main()
{
int n;
int occurrences = 0;
string::size_type start = 0;
string base_string, to_find;
base_string.reserve(200000);
to_find.reserve(100000);
for (size_t i = 0; i < 100000; i++){
base_string.push_back('a');
}
for (size_t i = 0; i < 100000; i++){
base_string.push_back('b');
}
for (size_t i = 0; i < 100000; i++){
to_find.push_back('b');
}
auto start_s = clock();
while ((start = base_string.find(to_find, start)) != string::npos) {
++occurrences;
start++;; // see the note
}
auto stop_s = clock();
std::cout << (stop_s - start_s) / double(CLOCKS_PER_SEC) * 1000;
cout << occurrences << endl;
std::getchar();
}
编译器,配置,您的计算机存在问题,但在您的代码中存在问题。