0

我有这个程序,它应该找到多个字符串的最长公共子字符串。它确实如此,但如果字符串很长(即> 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;
}

注意:我没有编写可以用后缀树解决这个问题的代码是有原因的(它们很大)。

4

3 回答 3

1

通常在优化方面,不同的方法可能是您唯一真正的选择,而不是尝试逐步改进当前的实现。这是我的想法:

  • 创建一个可能出现在最长公共子字符串中的有效字符列表。即,如果一个字符没有出现在所有字符串中,它就不能是最长公共子字符串的一部分。

  • 将每个字符串分成仅包含有效字符的多个字符串

  • 对于每个这样的字符串,创建每个可能的子字符串并将其添加到列表中

  • 过滤(与字符一样)所有未出现在所有列表中的字符串。

这显然在很大程度上取决于无效字符的数量。如果它为零,则这种方法根本没有帮助。

对您的代码的一些评论:不要试图过于聪明。编译器会优化很多,你真的不需要输入你register的代码。其次,您分配字符串然后覆盖它们(在 中readNumberSubstrings),这是完全没有必要的。第三,如果可以的话,通过 const 引用传递。第四,不要使用原始指针,特别是如果你从来没有delete []你的new []d 对象。使用std::vectors 代替,它在异常情况下表现良好(您可能会遇到,您经常使用字符串!)。

于 2013-09-20T12:31:26.490 回答
0

试试 Suffix 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++
    }
}
于 2013-12-16T08:31:29.220 回答
0

您必须使用后缀树。该结构将生成算法,该算法对 10 个具有 10000 个符号的字符串的工作时间约为 1 秒。

于 2013-09-20T11:52:48.683 回答