對於2字符串的Longest Common Subsequence,我在網上找到了很多示例,我相信我理解這個解決方案。
我不明白的是,N
字符串應用此問題的正確方法是什麼?以某種方式應用相同的解決方案?怎麼樣?解決方案不同嗎?什麼?一系列字符串的最長公共子序列
4
A
回答
4
當輸入具有任意數量的字符串時,此問題將變爲NP-hard。當輸入具有固定數量的字符串時,此問題變得易於處理只有。如果輸入具有k個字符串,我們可以通過使用k維陣列來應用相同的DP技術來存儲子問題的最優解。
1
找出2串A的最長公共子序列(LCS)和B,可以遍歷一個2維陣列對角像顯示在Link你張貼。數組中的每個元素都對應於找到子串A'和B'的LCS(A被其行號切割,B被其列號切割)的問題。這個問題可以通過計算數組中所有元素的值來解決。 您必須確定在計算數組元素的值時,計算給定值所需的所有子問題已經解決。這就是爲什麼你對角地穿過二維陣列的原因。
該解決方案可以縮放到找到N個字符串之間最長的公共子序列,但是這需要一種通用的方法來迭代N維的數組,以便任何元素只有在元素需要解決方案的所有子問題已解決。
除了以特殊順序迭代N維數組外,還可以遞歸地解決問題。對於遞歸,保存中間解決方案非常重要,因爲許多分支都需要相同的中間解決方案。我在C#
,這是否寫了一個小例子:
string lcs(string[] strings)
{
if (strings.Length == 0)
return "";
if (strings.Length == 1)
return strings[0];
int max = -1;
int cacheSize = 1;
for (int i = 0; i < strings.Length; i++)
{
cacheSize *= strings[i].Length;
if (strings[i].Length > max)
max = strings[i].Length;
}
string[] cache = new string[cacheSize];
int[] indexes = new int[strings.Length];
for (int i = 0; i < indexes.Length; i++)
indexes[i] = strings[i].Length - 1;
return lcsBack(strings, indexes, cache);
}
string lcsBack(string[] strings, int[] indexes, string[] cache)
{
for (int i = 0; i < indexes.Length; i++)
if (indexes[i] == -1)
return "";
bool match = true;
for (int i = 1; i < indexes.Length; i++)
{
if (strings[0][indexes[0]] != strings[i][indexes[i]])
{
match = false;
break;
}
}
if (match)
{
int[] newIndexes = new int[indexes.Length];
for (int i = 0; i < indexes.Length; i++)
newIndexes[i] = indexes[i] - 1;
string result = lcsBack(strings, newIndexes, cache) + strings[0][indexes[0]];
cache[calcCachePos(indexes, strings)] = result;
return result;
}
else
{
string[] subStrings = new string[strings.Length];
for (int i = 0; i < strings.Length; i++)
{
if (indexes[i] <= 0)
subStrings[i] = "";
else
{
int[] newIndexes = new int[indexes.Length];
for (int j = 0; j < indexes.Length; j++)
newIndexes[j] = indexes[j];
newIndexes[i]--;
int cachePos = calcCachePos(newIndexes, strings);
if (cache[cachePos] == null)
subStrings[i] = lcsBack(strings, newIndexes, cache);
else
subStrings[i] = cache[cachePos];
}
}
string longestString = "";
int longestLength = 0;
for (int i = 0; i < subStrings.Length; i++)
{
if (subStrings[i].Length > longestLength)
{
longestString = subStrings[i];
longestLength = longestString.Length;
}
}
cache[calcCachePos(indexes, strings)] = longestString;
return longestString;
}
}
int calcCachePos(int[] indexes, string[] strings)
{
int factor = 1;
int pos = 0;
for (int i = 0; i < indexes.Length; i++)
{
pos += indexes[i] * factor;
factor *= strings[i].Length;
}
return pos;
}
我的代碼示例可以進一步優化。許多被緩存的字符串都是重複的,有些是重複的,只增加了一個額外的字符。當輸入字符串變大時,這會佔用更多的空間。
對於輸入:"666222054263314443712", "5432127413542377777", "6664664565464057425"
的LCS返回是"54442"
相關問題
- 1. 3個字符串中最長的公共子序列
- 2. 查找2個字符串的最長公共子序列?
- 3. MySQL最長公共子字符串
- 4. 最長的公共子序列Algo
- 5. 最長的公共子序列算法
- 6. 最長公共子序列的界限
- 7. 最長的公共子序列printdDiff
- 8. Ocaml中最長的公共子序列
- 9. 最長的公共子序列差異
- 10. 最長公共子序列優化
- 11. 打印最長公共子序列
- 12. 最長公共子序列重現
- 13. 最長公共迴文子序列
- 14. Python:列表的最長公共子序列的長度
- 15. 非常大的字符串之間最長的公共子序列
- 16. 兩個字符串的所有可能的LCS(最長公共子序列)
- 17. 跨多個序列的最長公共子串
- 18. 三個序列的最長公共子序列int
- 19. 最長的公共子序列(還原序列)
- 20. 多個序列的最長公共子序列
- 21. 最長的公共子列表
- 22. 多序列比對(最長公共子序列)?
- 23. 使用遞歸列表的最長公共子序列
- 24. 查找唯一最長公共子序列的數量
- 25. 最長公共子序列長度(LCS)的快速(er)算法
- 26. 生成所有最長公共子字符串的列表和變化
- 27. 最長的公共子串與滾動散列
- 28. 最長公共子序列程序拋出一個字符串索引超出範圍錯誤
- 29. 如何找到多個字符串中最長的公共子字符串?
- 30. 來自兩個以上字符串的最長公共子字符串 - C++
一種可能的解決方案使用[最長遞增子(http://en.wikipedia.org/wiki/Longest_increasing_subsequence)。它在本書中有描述:[Dan Gusfield的字符串,樹和序列的算法](http://www.amazon.com/Algorithms-Strings-Trees-Sequences-Computational/dp/0521585198)(第12.5.4章) –