[英]What can I do to speed up this code (String Similarity)?
這是一個用C ++編寫的代碼,使用標准庫來查找字符串S的字符串相似性及其后綴。
雖然它提供了正確的輸出,但是對於大字符串這樣做需要花費很多時間。 這是代碼:
#include <iostream>
#include <string>
using namespace std;
int sim(string a, string b){
int count=0;
int sa=a.size();
int sb=b.size();
int iter;
if(sa>sb) iter=sb;
else iter=sa;
for(int i=0; i<iter; i++){
if (a[i]!=b[i]) break;
else count++;
}
return count;
}
int strsim(string a){
int sum=0;
int s=a.size();
for(int i=0; i<s; i++){
sum=sum+sim(a,a.substr(i));
}
return sum;
}
int main(){
int n;
cin >> n;
string a[n];
for(int i=0; i<n; i++){
cin >> a[i];
}
for(int i=0; i<n; i++){
cout << strsim(a[i]) << '\n';
}
}
約束:每個字符串的長度最多為100000,僅包含小寫字符和測試用例的數量,'n'不能超過10。
樣本I / O:
輸入:
1 ababaa
輸出:
11
即, 6 + 0 + 3 + 0 + 1 + 1 = 11
您當前的代碼計算長度為L的單個字符串,在O(L^3)
(substr采用線性運行時間)。 更不用說由於低效的字符串傳遞而導致上述復雜性的高成本。
您的算法可以簡單地簡化為查找具有所有后綴的字符串的最長公共前綴。 這可以使用Suffix Aray輕松完成。 這個概念無法解釋為答案,因此我強烈建議您閱讀本文 。
子優化且簡單的代碼后綴陣列解決方案將具有O(Llg^2(L))
(L =字符串長度)構造時間和O(1)
時間來使用范圍最小查詢來查詢2個后綴的最長公共前綴。 請注意,整個字符串本身就是它自己的后綴。 在您的情況下,您需要為每個字符串進行L查詢。 因此,一個字符串的總復雜度將為O(Llg^2(L)) + O(L)
。
如果想進一步改進,可以使用基數排序將結構時間減少到O(Llg(L))
,或者將結構時間減少到O(L)
( 讀取 )
您在這里獲得的最大成本是您按值傳遞字符串 - 這意味着每次調用“sim”都會創建兩個全新的字符串並將數據復制到它們。 你應該消除它並用pass-by-reference替換它。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
size_t compareSubstring(const std::string& str, size_t offset)
{
size_t count = 0;
std::string::const_iterator lhsIt = str.begin();
std::string::const_iterator rhsIt = str.begin() + offset;
for ( ; rhsIt != str.end() ; ++lhsIt, ++rhsIt ) {
if (*lhsIt != *rhsIt)
break;
++count;
}
return count;
}
int compareString(const string& str)
{
size_t count = 0;
const size_t length = str.size();
for(size_t i = 0; i < length; ++i) {
count += compareSubstring(str, i);
}
return count;
}
int main()
{
size_t numStrings = 0;
std::cin >> numStrings;
std::vector<std::string> strings;
strings.resize(numStrings);
for(size_t i = 0; i < numStrings; ++i) {
std::cin >> strings[i];
}
for(size_t i = 0; i < numStrings; ++i) {
std::cout << compareString(strings[i]) << std::endl;
}
}
這里有效率(不進入FFT區域):
sum_i = 0 ^ j sum_j = 0 ^ s f_i,j
int strsim(const string &a){
int s=a.size();
int sum=0;
for(int i=0; i<s; i++){
for (int j=i;j<s;++j){
if (a[j-i]!=a[i]) break;
sum ++;
}
}
return sum;
}
我知道它看起來與你的代碼不同,但是(除非我有一個bug)它應該返回相同的東西。
試一試,讓我知道!
首先,你應該檢查是否有更好的算法。 然后,根據您准備投資的數量和可移植性,您可能需要手動向量化代碼,如果編譯器沒有設法執行此操作。 使用gcc內在函數(參見例如本教程 )我已經能夠在類似的代碼上獲得x6加速。
在strsim()函數中再添加一行可以減少對sim()函數的一些額外函數調用。 我們知道,當我們談論性能時,函數調用的成本(消耗額外的內存和處理“序幕”和“結尾”機制)是相當可觀的。
因此,只有當你的情況“a”和“a.substring”中兩個字符串的第一個字符相等時才調用sim函數。
int strsim(string a){
int sum=0;
int s=a.size();
for(int i=0; i<s; i++){
if(a[i] == a[0]) //add this extra line
sum=sum+sim(a,a.substr(i));
}
return sum;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.