也就是:編輯距離=max(字符串1的長度,字符串2的長度)-兩字符串的最長公共長度。
好的,現在重點就是要計算兩字符串的最長公共長度。我是這樣考慮的,
如果要計算str1與str2的最長公共長度。我首先從str1的字符從左到右一個個來,假設str1前m個字符與str2前n個字符的最長公共長度爲dist[m][n],
那麼假設str1前m+1個字符與str2前n+1個字符的最長公共長度就爲以下兩種情況了:
(1)str1[m+1]==str2[n+1],這個時候的dist[m+1][n+1]就應該是dist[m][n]+1了;
(2) str1[m+1]!=str2[n+1] ,這個時候的dist[m+1][n+1]就應該是dist[m][n+1]和dist[m+1][n]中較大點的那個了。好了,就是這樣思想,
這是一種動態規劃的想法,下面給出動態規劃狀態轉移方程:
dist[m][n]=
(1):dist[m-1][n-1],str1[m]==str2[n];
(2):max(dist[m-1][n],dist[m][n-1]),else 代碼1:
//求解兩字符串的編輯距離
public static int EditDistance(String str1,String str2) {
char[] strs1=str1.toCharArray();//轉換爲字符數組
char[] strs2=str2.toCharArray();//轉換爲字符數組
int[][] dist=new int[strs1.length+1][strs2.length+1];//定義距離二維數組,多定義一維是爲了避免邊界檢測
int i,j,temp;
for(i=0;i<=strs1.length;i++) dist[i][0]=0;//初始化邊界值
for(i=0;i<=strs2.length;i++) dist[0][i]=0;//初始化邊界值
for(i=1;i<=strs1.length;i++) {
for(j=1;j<=strs2.length;j++)
{
if(strs1[i-1]==strs2[j-1])//如果兩字符相等,則取dist[i-1][j-1]+1
{
temp=dist[i-1][j-1]+1;
}
else//不等,則取dist[i-1][j]與dist[i][j-1]的最大值
{
temp=dist[i][j-1];
if(dist[i-1][j]>temp) temp=dist[i-1][j];
}
dist[i][j]=temp;
}
}
temp=dist[strs1.length][strs2.length];
if(strs1.length>strs2.length)
return strs1.length-temp;
else
return strs2.length-temp;
}
對這個程序作出時空分析的時候發現,時間複雜度爲O(mn),空間複雜度也爲O(mn),有沒有改進的餘地呢?
其實還是有的。注意到,每次狀態轉移的時候,我們只需考慮dist[i-1][*]這一維數組和dist[i][*]這一維,所以我們時候只用兩個一維數組就可以了呢,
然後使用兩個數組一次輪倒(輪倒是我創造的詞,意思就是輪流的倒來倒去),其實都不用輪倒,只要每次把[i][*]的結果用[i-1][*]保存就好了!
這與求兩個字符串的公共子序列要區分開,見http://blog.csdn.net/shandianling/article/details/7888050<br/>
但 求你方法與求公共子序列類似,而且要簡單一點。<br/>
方法:動態規劃.
循環遍歷兩個字符串,查找當s1[i]==s2[k] 的情況 然後保存在c[i][k]中,c[i][k]=c[i-1][k-1]+1 最後我們會得到類似以下矩陣
OK,結果可以看出來了。
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- //求公共子串(連續),注意跟求公共子序列有區別
- int lcstr( const char* s1,const char* s2)
- {
- //clen保存公共子串的最大長度,s1_Mindex保存 s1公共子串的最後一個元素的位置
- int len1,len2,i,k,cLen=1,s1_Mindex=0;
- int **c;
- if(s1==NULL || s2==NULL) return -1;
- len1=strlen(s1);
- len2=strlen(s2);
- if(len1< 1 || len2 < 1) return -1;
- c=malloc(sizeof(int*)*len1);
- for(i=0;i<len1;i++)
- {
- c[i]=(int *)malloc(len2*sizeof(int));
- memset(c[i],0,len2*sizeof(int));
- }
- /**********init end!*************/
- for(i=0;i<len1;i++)
- {
- for(k=0;k<len2;k++)
- {
- if(i==0 || k==0)
- {
- if(s1[i]==s2[k]) c[i][k]=1;
- else c[i][k]=0;
- }
- else
- {
- if (s1[i] == s2[k])
- {
- c[i][k] = c[i - 1][k - 1] + 1;
- if (cLen < c[i][k])
- {
- cLen = c[i][k];
- s1_Mindex = i;
- }
- }
- }
- }
- }
- //*************//
- // printf the one of lcs 只是其中一條,如果存在多條。
- for(i=0;i<cLen;i++)
- {
- printf("%c",*(s1+s1_Mindex-cLen+1+i));
- }
- /*****free array*************/
- for(i=0;i<len1;i++)
- free(c[i]);
- free(c);
- return cLen;
- }
- int main(void) {
- char a[]="abcgooglecba";
- char b[]="cbagoogleABVC";
- printf("\nlcstr = %d\n",lcstr(a,b));
- return 0;
- }
/*========================================================
子數整數
源程序名 num.??? (pas,c,cpp)
可執行文件名 num.exe
輸入文件名 num.in
輸出文件名 num.out
對於一個五位數a1a2a3a4a5,可將其拆分爲三個子數:
sub1=a1a2a3
sub2=a2a3a4
sub3=a3a4a5
例如,五位數20207可以拆分成
sub1=202
sub2=020(=20)
sub3=207
現在給定一個正整數K,要求你編程求出10000到30000之間所有滿足下述條件的五位數,
條件是這些五位數的三個子數sub1,sub2,sub3都可被K整除。
輸入
輸入由鍵盤輸入,輸入僅一行,爲正整數K(0<K<1000)。
輸出
輸出到文件,輸出文件的每一行爲一個滿足條件的五位數,要求從小到大輸出。
不得重複輸出或遺漏。如果無解,則輸出“No”。
樣例
num.in
15
num.out
22555
25555
28555
30000
==========================================================*/
#include <stdio.h>
#include <string.h>
/*從字符串的左邊截取n個字符*/
char * left(char *dst,char *src, int n)
{
char *p = src;
char *q = dst;
int len = strlen(src);
if(n>len) n = len;
/*p += (len-n);*/ /*從右邊第n個字符開始*/
while(n--) *(q++) = *(p++);
*(q++)='\0'; /*有必要嗎?很有必要*/
return dst;
}
/*從字符串的中間截取n個字符*/
char * mid(char *dst,char *src, int n,int m) /*n爲長度,m爲位置*/
{
char *p = src;
char *q = dst;
int len = strlen(src);
if(n>len) n = len-m; /*從第m個到最後*/
if(m<0) m=0; /*從第一個開始*/
if(m>len) return NULL;
p += m;
while(n--) *(q++) = *(p++);
*(q++)='\0'; /*有必要嗎?很有必要*/
return dst;
}
/*從字符串的右邊截取n個字符*/
char * right(char *dst,char *src, int n)
{
char *p = src;
char *q = dst;
int len = strlen(src);
if(n>len) n = len;
p += (len-n); /*從右邊第n個字符開始*/
while(*(q++) = *(p++));
return dst;
}
void main()
{
FILE * p;
int i,k,outi,count=0;
int sub1,sub2,sub3;
char *strsub1,*strsub2,*strsub3,*strtempnum,*a,*b,*c;
if((p = fopen("num.out", "ab+")) == NULL)
{
printf("open file fail!");
getch();
exit();
}
printf("Please input int number(0<K<1000):");
scanf("%d",&k);
for(outi=10000;outi<=30000;outi++)
{
itoa(outi,strtempnum,10);
left(strsub1,strtempnum,3);
mid(strsub2,strtempnum,3,1);
right(strsub3,strtempnum,3);
/*
a=strsub1;
b=strsub2;
c=strsub3;
printf("strsub1=%s,strsub2=%s,strsub3=%s\n",a,b,c);
*/
sub1=atoi(strsub1);
sub2=atoi(strsub2);
sub3=atoi(strsub3);
/*
printf("sub1=%d , sub2=%d , sub3=%d \n\n",sub1,sub2,sub3);
printf("sub1k=%d , sub2k=%d , sub3k=%d \n\n" , sub1 % k,sub2 % k,sub3 % k);
getch();
*/
if((sub1%k)==0 && (sub2%k)==0 && (sub3%k)==0)
{
fprintf(p,"%d\n",outi);
count++;
printf("outi=%d\n",outi);
}
else
{
fprintf(p,"%s\n","NO");
}
}
printf("Count=%d OK",count);
fclose(p);
getch();
}
char* substr(const char*str,unsigned start, unsigned end)
{
unsigned n = end - start;
static char stbuf[256];
strncpy(stbuf, str + start, n);
stbuf[n] = 0;
return stbuf;
}
c中strncpy也可以實現這個功能
char *strncpy(char *dest, char *src, int n);
strncpy( strtemp,str+n , m )
--strtemp字符串變量,截取後的字符串存放處
--str 字符串變量,要截取的字符串
--n ,int 型,
-- str+n, 表示從第n 位開始截取字符串
--m,int型,表示截取m位
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/**
*
* @author: [email protected]
* @reference: lovesnow1314@http://community.csdn.net/Expert/TopicView3.asp?id=5198221
*
* 用新子串newstr替換源字符串src中的前len個字符內所包含的oldstr子串
*
* @param char* dest 目標串,也就是替換後的新串
* @param const char* src 源字符串,被替換的字符串
* @param const char* oldstr 舊的子串,將被替換的子串
* @param const char* newstr 新的子串
* @param int len 將要被替換的前len個字符
*
* @return char* dest 返回新串的地址
*
*/
char *strreplace(char *dest, char *src, const char *oldstr, const char *newstr, size_t len)
{
//如果串相等,則直接返回
if(strcmp(oldstr, newstr)==0)
return src;
//子串位置指針
char *needle;
//臨時內存區
char *tmp;
//把源串地址賦給指針dest,即讓dest和src都指向src的內存區域
dest = src;
//如果找到子串, 並且子串位置在前len個子串範圍內, 則進行替換, 否則直接返回
while((needle = strstr(dest, oldstr)) && (needle -dest <= len))
{
//分配新的空間: +1 是爲了添加串尾的'\0'結束符
tmp=(char*)malloc(strlen(dest)+(strlen(newstr)-strlen(oldstr))+1);
//把src內的前needle-dest個內存空間的數據,拷貝到arr
strncpy(tmp, dest, needle-dest);
//標識串結束
tmp[needle-dest]='\0';
//連接arr和newstr, 即把newstr附在arr尾部, 從而組成新串(或說字符數組)arr
strcat(tmp, newstr);
//把src中 從oldstr子串位置後的部分和arr連接在一起,組成新串arr
strcat(tmp, needle+strlen(oldstr));
//把用malloc分配的內存,複製給指針retv
dest = strdup(tmp);
//釋放malloc分配的內存空間
free(tmp);
}
return dest;
}
int main()
{
char *str="wo i love iyou";
char *old="i";
char *new="ILOVEYOUYA";
char *dest;
//分配內存空間: 大小 == src的長度 + newstr和oldstr長度差(可能是正負或0)+1
printf("%s\n",strreplace(dest, str, old, new,1));
printf("%s\n",strreplace(dest, str, old, new,5));
printf("%s\n",strreplace(dest, str, old, new,40));
return 0;
}