字符串问题
1.左旋问题
2.字符包含问题
3.字符匹配KMP
4.编辑距离
5.最大回文子串,公共子串
6.最大公共子序列,回文子序列,上升子序列
7.基本字符串函数实现
8.大整数的加,减,乘,除,模
9.合法回文,数字串
10.正则匹配,最长公共前缀,简化路经
1) 左旋字符串
定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部,如把字符串abcdef左旋转2位得到字符串cdefab。请实现字符串左旋转的函数,要求对长度为n的字符串操作的时间复杂度为O(n),空间复杂度为O(1).
思路一、暴力移位法
voidleftshiftone(char *s,int n) {
char t = s[0];
//保存第一个字符
for (int i = 1; i <n; ++i) {
s[i - 1] = s[i];
}
s[n - 1] = t;
}
如此,左移m位的话,可以如下实现:
void leftshift(char*s,int n,int m) {
while (m--) {
leftshiftone(s,n);
}
}
思路二、指针翻转法
#include<iostream>
#include<string>
usingnamespacestd;
voidrotate(string&str,intm) {
if(str.length() == 0 || m <= 0)
return;
intn = str.length();
if(m % n <= 0)
return;
intp1 = 0, p2 = m;
intk = (n - m) - n % m;
//交换p1,p2指向的元素,然后移动p1,p2
while(k--) {
swap(str[p1],str[p2]);
p1++;
p2++;
}
//重点,都在下述几行。
//处理尾部,r为尾部左移次数
intr = n - p2;
while(r--) {
inti = p2;
while(i> p1)
{
swap(str[i],str[i - 1]);
i--;
}
p2++;
p1++;
}
//比如一个例子,abcdefghijk
// p1p2
//当执行到这里时,defghia b c j k
//p2+m出界了,
//r=n-p2=2,所以以下过程,要执行循环俩次。
//第一次:j步步前移,abcjk->abjck->ajbck->jabck
//然后,p1++,p2++,p1指a,p2指k。
//p1 p2
//第二次:defghij a b c k
//同理,此后,k步步前移,abck->abkc->akbc->kabc。
}
//在尾部处理作了一点不同的处理优化
voidrotate(string&str,intm) {
if(str.length() == 0 || m < 0)
return;
//初始化p1,p2
intp1 = 0, p2 = m;
intn = str.length();
//处理m大于n
if(m % n == 0)
return;
//循环直至p2到达字符串末尾
while(true){
swap(str[p1],str[p2]);
p1++;
if(p2 < n - 1)
p2++;
else
break;
}
//处理尾部,r为尾部循环左移次数
intr = m - n % m;
while(r--)
//r = 1.
//外循环执行一次
{
inti = p1;
chartemp = str[p1];
while(i < p2)
//内循环执行俩次
{
str[i]= str[i + 1];
i++;
}
str[p2]= temp;
}
}
思路三,三步翻转法
char*invert(char*start,char*end) {
chartmp, *ptmp = start;
while(start != NULL && end != NULL && start < end) {
tmp= *start;
*start= *end;
*end= tmp;
start++;
end--;
}
returnptmp;
}
char*left(char*s,intpos)//pos为要旋转的字符个数,或长度,下面主函数测试中,pos=3。
{
intlen = strlen(s);
invert(s,s + (pos - 1));
//如上,X->X^T,即abc->cba
invert(s+ pos, s + (len - 1));//如上,Y->Y^T,即def->fed
invert(s,s + (len - 1));
//如上,整个翻转,(X^TY^T)^T=YX,即cbafed->defabc。