字符串操作

依据上面的分析,那么我们主要就是要找到两字符串的公共字符串的大小,然后用两字符串的长度的少大值减去它就可以了。
也就是:编辑距离=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,结果可以看出来了。

[cpp]  view plain copy
  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: cnscn@163.com
* @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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值