子字串的定義和子串行的定義類似,但要求是連續分布在其他字串中。比如輸入兩個字串bdcaba和abcbdab的最長公共字串有bd和ab,它們的長度都是2。
最長公共子字串共有兩種解決方法,下面具體說說我的思路
方法一:
longest common substring和longest common subsequence是有區別的
x =
y =
x和y的longest common sequence為,長度為4
x和y的longest common substring為 長度為2
其實substring問題是subsequence問題的特殊情況,也是要找兩個遞增的下標序列
和 使xi1 == yj1
xi2 == yj2
......
xik == yjk
與subsequence問題不同的是,substring問題不光要求下標序列是遞增的,還要求每次
遞增的增量為1, 即兩個下標序列為: 和
模擬subquence問題的動態規劃解法,substring也可以用動態規劃解決,令
c[i][j]表示xi和yi的最大substring的長度,比如
x =
y =
c[1][1] = 1
c[2][2] = 2
c[3][3] = 0
c[4][4] = 1
動態轉移方程為:
如果xi == yj, 則 c[i][j] = c[i-1][j-1]+1
如果xi ! = yj, 那麼c[i][j] = 0
最後求longest common substring的長度等於
max完整的**如下:
[cpp]view plain
copy
/**
找出兩個字串的最長公共連續子串的長度
** author :liuzhiwei
** data :2011-08-16
**/#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int longest_common_substring(char *str1, char *str2)
} } //輸出公共子串
char s[1000];
k=max;
i=x-1,j=y-1;
s[k--]='\0';
while(i>=0 && j>=0)
else
//只要有乙個不相等,就說明相等的公共字元斷了,不連續了
break;
} printf("最長公共子串為:");
puts(s);
for(i = 0; i
delete c[i];
delete c;
return max;
} int main(void)
效果圖如下:
方法二:
將字串s1和s2分別寫在兩把直尺上面(我依然用s1,s2來表示這兩把直尺),然後將s1固定,s2的頭部和s1的尾部對齊,然後逐漸移動直尺s2,比較重疊部分的字串中的公共子串的長度,直到直尺s2移動到s1的頭部。在這個過程中求得的最大長度就是s1、s2最大子串的長度。
下圖是求解過程的圖示(下圖有點錯誤,應該是將s2從右往左移動),藍色部分表示重疊的字串,紅色的部分表示重疊部分相同的子串
其中s1="shaohui",s2="ahui",最後求得的結果為3
完整的**如下:
[cpp]view plain
copy
/**
找出兩個字串的最長公共連續子串的長度
** author :liuzhiwei
** data :2011-08-16
**/#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int longest_common_substring(char *str1, char *str2)
} max = curmax > max ? curmax : max;
} return max;
} int main(void)
效果圖如下:
稍微改動一下,便可以輸出公共子串了,就是要儲存一下連續公共子串最後乙個字元在其中乙個字串中的下標位置:
[cpp]view plain
copy
/**
找出兩個字串的最長公共連續子串的長度
** author :liuzhiwei
** data :2011-08-16
**/#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int longest_common_substring(char *str1, char *str2)
curmax = 0;
} }
//max = curmax > max ? curmax : max;
if(curmax > max)
} //輸出公共子串
char s[1000];
for(i=0;is[i]=str1[k-max+1+i]; //公共字串在str1中的下標起始位置為k-max+1,結束位置為k
s[i]='\0';
printf("最長公共子串為:");
puts(s);
return max;
} int main(void)
效果圖如下:
擴充套件:子串也可以是反串,比如hdoj 1238
題目意思是要搜尋最長的子串
給出一系列字串,幾個子串可以是反串
rose
orchid
這裡最長的子串是 ro 跟or 長度為2。
如果窮舉搜尋的話,肯定過不了。
所以可以找出所有字串中最短的串,列舉最短的字串的子串
判斷是否都是別的字串的子串,求出最大長度即可。。
[cpp]view plain
copy
/**
找出兩個字串的最長公共連續子串的長度
** author :liuzhiwei
** data :2011-08-16
**/#include "stdio.h"
#include "string.h"
#include "stdlib.h"
char str[100][100];
int k;
int match(int start,int end,int n) //最短字串中的起點下標、終點下標,字串總數
if(p>end) //如果全部相等,則匹配成功,終止
break;
for(p=end,h=j;p>=start;p--,h++) //逆序判斷子串
if(p//如果全部相等,則匹配成功,終止
break;
} if(j>len-1-end+start) //如果搜尋完畢都沒終止,即無匹配
return 0;
} return 1;
} int main(void)
} for(i=0;i//對最短字串的連續字串進行匹配查詢
} if(flag==1)
break;
} printf("%d\n",minlen-i);
} system("pause");
return 0;
}
程式設計師面試100題之七 最長公共子字串
子字串的定義和子串行的定義類似,但要求是連續分布在其他字串中。比如輸入兩個字串bdcaba和abcbdab的最長公共字串有bd和ab,它們的長度都是2。最長公共子字串共有兩種解決方法,下面具體說說我的思路 方法一 longest common substring和longest common sub...
程式設計師面試100題之十二 求陣列中最長遞增子串行
寫乙個時間複雜度盡可能低的程式,求乙個一維陣列 n個元素 中最長遞增子串行的長度。例如 在序列1,1,2,3,4,5,6,7中,其最長遞增子串行為1,2,4,6。分析與解法 根據題目要求,求一維陣列中的最長遞增子串行,也就是找乙個標號的序列b 0 b 1 b m 0 b 0 解法一根據無後效性的定義...
程式設計師面試100題之十二 求陣列中最長遞增子串行
寫乙個時間複雜度盡可能低的程式,求乙個一維陣列 n個元素 中最長遞增子串行的長度。例如 在序列1,1,2,3,4,5,6,7中,其最長遞增子串行為1,2,4,6。分析與解法 根據題目要求,求一維陣列中的最長遞增子串行,也就是找乙個標號的序列b 0 b 1 b m 0 b 0 解法一根據無後效性的定義...