字符串操作

依據上面的分析,那麼我們主要就是要找到兩字符串的公共字符串的大小,然後用兩字符串的長度的少大值減去它就可以了。
也就是:編輯距離=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,結果可以看出來了。

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. //求公共子串(連續),注意跟求公共子序列有區別  
  5. int lcstr( const char* s1,const char* s2)  
  6. {  
  7.     //clen保存公共子串的最大長度,s1_Mindex保存 s1公共子串的最後一個元素的位置  
  8.     int len1,len2,i,k,cLen=1,s1_Mindex=0;  
  9.     int **c;  
  10.     if(s1==NULL || s2==NULL) return -1;  
  11.     len1=strlen(s1);  
  12.     len2=strlen(s2);  
  13.     if(len1< 1 || len2 < 1) return -1;  
  14.     c=malloc(sizeof(int*)*len1);  
  15.     for(i=0;i<len1;i++)  
  16.     {  
  17.         c[i]=(int *)malloc(len2*sizeof(int));  
  18.         memset(c[i],0,len2*sizeof(int));  
  19.     }  
  20.     /**********init end!*************/  
  21.     for(i=0;i<len1;i++)  
  22.     {  
  23.         for(k=0;k<len2;k++)  
  24.         {  
  25.             if(i==0 || k==0)  
  26.             {  
  27.                 if(s1[i]==s2[k]) c[i][k]=1;  
  28.                 else c[i][k]=0;  
  29.             }  
  30.             else  
  31.             {  
  32.                 if (s1[i] == s2[k])  
  33.                 {  
  34.                     c[i][k] = c[i - 1][k - 1] + 1;  
  35.                     if (cLen < c[i][k])  
  36.                     {  
  37.                         cLen = c[i][k];  
  38.                         s1_Mindex = i;  
  39.                     }  
  40.                 }  
  41.             }  
  42.         }  
  43.     }  
  44.     //*************//  
  45.     // printf the one of lcs 只是其中一條,如果存在多條。  
  46.     for(i=0;i<cLen;i++)  
  47.     {  
  48.         printf("%c",*(s1+s1_Mindex-cLen+1+i));  
  49.     }  
  50.     /*****free array*************/  
  51.     for(i=0;i<len1;i++)  
  52.         free(c[i]);  
  53.     free(c);  
  54.     return cLen;  
  55.   
  56. }  
  57. int main(void) {  
  58.     char a[]="abcgooglecba";  
  59.     char b[]="cbagoogleABVC";  
  60.     printf("\nlcstr = %d\n",lcstr(a,b));  
  61.     return 0;  
  62. }  



/*========================================================
子數整數
源程序名 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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章