[英]Optimisation ideas - Longest common substring
我有這個程序,應該找到許多字符串的最長公共子字符串。 可以,但是如果字符串很長(即,> 8000個字符長),則它會緩慢運行(1.5秒)。 有什么辦法可以優化嗎?
程序是這樣的:
//#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <cassert>
using namespace std;
const unsigned short MAX_STRINGS = 10;
const unsigned int MAX_SIZE=10000;
vector<string> strings;
unsigned int len;
string GetLongestCommonSubstring( string string1, string string2 );
inline void readNumberSubstrings();
inline const string getMaxSubstring();
void readNumberSubstrings()
{
cin >> len;
assert(len > 1 && len <=MAX_STRINGS);
strings.resize(len);
for(register unsigned int i=0; i<len;i++)
strings[i]=string(MAX_SIZE,0);
for(register unsigned int i=0; i<len; i++)
cin>>strings[i];
}
const string getMaxSubstring()
{
string maxSubstring=strings[0];
for(register unsigned int i=1; i < len; i++)
maxSubstring=GetLongestCommonSubstring(maxSubstring, strings[i]);
return maxSubstring;
}
string GetLongestCommonSubstring( string string1, string string2 )
{
const int solution_size = string2.length()+ 1;
int *x=new int[solution_size]();
int *y= new int[solution_size]();
int **previous = &x;
int **current = &y;
int max_length = 0;
int result_index = 0;
int j;
int length;
int M=string2.length() - 1;
for(register int i = string1.length() - 1; i >= 0; i--)
{
for(register int j = M; j >= 0; j--)
{
if(string1[i] != string2[j])
(*current)[j] = 0;
else
{
length = 1 + (*previous)[j + 1];
if (length > max_length)
{
max_length = length;
result_index = i;
}
(*current)[j] = length;
}
}
swap(previous, current);
}
string1[max_length+result_index]='\0';
return &(string1[result_index]);
}
int main()
{
readNumberSubstrings();
cout << getMaxSubstring() << endl;
return 0;
}
注意 :我之所以沒有寫代碼來解決后綴樹(它們很大)是有原因的。
通常,在進行優化時,您可能唯一的選擇就是采用其他方法,而不是嘗試逐步改進當前的實現。 這是我的主意:
創建可能出現在最長的公共子字符串中的有效字符列表。 即,如果字符未出現在所有字符串中,則該字符不能成為最長公共子字符串的一部分。
將每個字符串分成僅包含有效字符的多個字符串
對於每個這樣的字符串,創建每個可能的子字符串,並將其也添加到列表中
過濾(與字符一樣)所有不在所有列表中顯示的字符串。
顯然,其復雜性在很大程度上取決於無效字符的數量。 如果為零,則此方法完全沒有幫助。
關於您的代碼的一些評論:不要試圖變得過於聰明。 編譯器將進行大量優化,實際上不需要您在代碼中添加register
。 其次,分配字符串然后覆蓋它們(在readNumberSubstrings
),這完全沒有必要。 第三,如果可以的話,通過const引用傳遞。 第四,不要使用原始指針,特別是如果您從不delete []
new []
d對象。 使用std::vector
代替,它在異常情況下表現良好(您可能會遇到,您經常使用字符串!)。
您必須使用后綴樹。 該結構將生成算法,該算法對於帶有10000個符號的10個字符串大約工作1秒。
嘗試使用后綴Arraya,它們占用的內存與輸入字符串一樣多(盡管取決於您的文本編碼),並且可以在線性時間內快速構建。
http://en.wikipedia.org/wiki/Suffix_array
這是我的JavaScript代碼
function LCS(as, bs, A, B) {
var a = 0, b = 0, R = [], max = 1
while (a < A.length && b < B.length) {
var M = cmpAt(as, bs, A[a], B[b])
if (M.size > 0) {
if (M.ab < 0) {
var x = b; while (x < B.length) {
var C = cmpAt(as, bs, A[a], B[x])
if (C.size >= M.size) { if (C.size >= max) max = C.size, R.push([a, x, C.size]) } else break
x++
}
} else {
var x = a; while (x < A.length) {
var C = cmpAt(as, bs, A[x], B[b])
if (C.size >= M.size) { if (C.size >= max) max = C.size, R.push([x, b, C.size]) } else break
x++
}
}
}
if (M.ab < 0) a++; else b++
}
R = R.filter(function(a){ if (a[2] == max) return true })
return R
}
function cmpAt(a, b, x, y) {
var c = 0
while (true) {
if (x == a.length) {
if (y == b.length) return { size: c, ab: 0 }
return { size: c, ab: -1 }
}
if (y == b.length) return { size: c, ab: 1 }
if (a.charCodeAt(x) != b.charCodeAt(y)) {
var ab = 1;
if (a.charCodeAt(x) < b.charCodeAt(y)) ab = -1
return { size: c, ab: ab }
}
c++, x++, y++
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.