也就是:编辑距离=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: 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;
}