1.实现一个函数,可以左旋字符串中的k个字符。
AABCD左旋一个字符得到ABCDA
AABCD左旋两个字符得到BCDAA
第一种方法:
思路:先将一个字符串左移一位,可以使用一层for循环来实现,
然后每次都可以调用这层循环,调用移位的次数,还有就是,
循环次数如果大于字符串的长度,会重复执行一些无用的
操作,所以给step模上字符串的长度,就可以产生一个小于
字符串长度的数字。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
void str_shift(char *str,int len, int step)
{
int i = 0;
int j = 0;
char tmp = 0;
step %= len;//step为0到(len - 1)的一个数字,提高了移位时的效率
assert(str);
assert(len > 1);
for (j = 0; j < step; j++)//外层循环实现左移step位
{
tmp = str[0];
for (i = 0; i < len - 1; i++)//内层循环实现了左移一次
{
str[i] = str[i+1];
}
str[i] = tmp;
}
}
int main()
{
char msg[] = "ABCD1234";
int k = 0;
printf("Please Enter:>");
scanf("%d",&k);
printf("before : %s\n",msg);
str_shift(msg,strlen(msg), k);
printf("shift_after : %s\n",msg);
system("pause");
return 0;
}
第二种方法:
思路:将一个字符串从它要移位的位置分为两个部分,
(例如:字符串:ABCD1234 要移3位 则将其分为 ABC D1234),
然后将它的左右两边的子字符串各自逆置(CBA 4321D),
然后将逆置后的结果(D1234ABC)再进行整体逆置, 这个结果就是
将原字符串左移3位后的结果。
其实就是将前后两部分各自逆置了两次,然而却把前面的一部分旋转到了这个字符串的尾部。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
void swap(char *start, char *end)//交换两个字符
{
*start ^= *end;
*end ^= *start;
*start ^= *end;
}
void reverse(char *start, char *end)
{
assert(start);
assert(end);
while (start < end)//将字符串逆置
{
swap(start,end);
start++,end--;
}
}
void str_shift(char *str,int len, int step)
{
char *middle = NULL;
step %= len;//使得移位的步数小于字符串的长度
middle = str + step - 1;//middle将字符串分为两部分
assert(str);
assert(len > 1);
assert(step > 0);
reverse(str,middle);//将分开的左半部分逆置
reverse(middle +1, str + len - 1);//将分开的右半部分逆置
reverse(str,str + len -1);//将整体逆置
}
int main()
{
char msg[] = "ABCD1234";
int k = 0;
printf("Please Enter:>");
scanf("%d",&k);
printf("before : %s\n",msg);
str_shift(msg,strlen(msg), k);
printf("shift_after : %s\n",msg);
system("pause");
return 0;
}
第三种方法:
思路:使用双重字符串(例如:ABCDABCD),如果需要左旋1位,
则让字符串的首地址加上1,从此处截取字符串长度的字符(BCDA),
则这个结果就是左旋一位后的结果,但是这种方法不适合长度特别大的
字符串。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
//------双重字符串
//1234------1 2341234---左旋一位----(str+1,str+len-1)
//左旋2位-----(str +2,str+ 2 +len -1)
// 左旋step位----(str + k,str + step -1)
void str_shift(char *str,int len, int step)
{
char *newstr = NULL;
assert(str);
assert(len > 1);//检查len是否大于1
assert(step > 0 );//检查要左旋的位数是否大于0
step %= len;
newstr = (char *)malloc(sizeof(char) * len * 2 +1);//开辟双重字符串的空间
strcpy(newstr,str);//将原字符串拷贝到新的字符串中
strcat(newstr,str);//将原字符串连接到新字符串中,使之产生双重字符串
strncpy(str,newstr + step,len);//从左旋的位数开始,复制字符串长度个字符
free(newstr);//在堆上开辟的空间需要自行释放
newstr = NULL;
}
int main()
{
char msg[] = "ABCD1234";
int k = 0;
printf("Please Enter:>");
scanf("%d",&k);
printf("before : %s\n",msg);
str_shift(msg,strlen(msg), k);
printf("shift_after : %s\n",msg);
system("pause");
return 0;
}
2.判断一个字符串是否为另外一个字符串旋转之后的字符串。
例如:给定s1 = AABCD和s2 = BCDAA,返回1,给定s1=abcd和s2=ACBD,返回0.
AABCD左旋一个字符得到ABCDA
AABCD左旋两个字符得到BCDAA
AABCD右旋一个字符得到DAABC
AABCD右旋两个字符得到CDAAB
分析:可以在第一道题的思路上向下延伸:
要使得一个字符串是另一个字符串旋转之后得到的字符串,首先
两个字符串长度必须一样长,不然一定不会是旋转之后得到的字符串,
如果一个字符串是另一个字符串经过旋转可以得到的,那么这个字符串
一定是它双重字符串的一个字串。
例如:(ABCD)与(CDAB)——双重字符串(AB**CDAB**CD),
由此可以看出它是它的双重字符串的一个子串。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
int is_sub_str(char *str,char *arr)
{
char *newstr = NULL;
int len = strlen(str);
assert(str);
assert(arr);
assert(len > 0);//检查len是否大于0
if (strlen(str) == strlen(arr))
{
newstr = (char *)malloc(sizeof(char) * len * 2 +1);//开辟双重字符串的空间
strcpy(newstr,str);//将原字符串拷贝到新的字符串中
strcat(newstr,str);//将原字符串连接到新字符串中,使之产生双重字符串
if (strstr(newstr,arr) == NULL)//如果在双重字符串中没有找到arr这个字符串
{ //则返回0
return 0;
}
return 1;//如果在双重字符串中找到了arr字符串,则返回1
free(newstr);//在堆上开辟的空间需要自行释放
newstr = NULL;
}
return 0;
}
int main()
{
char msg[] = "ABCD1234";
char str[] = "CD1234AB";
printf("is sub str : %d",is_sub_str(msg,str));//是---返回1 不是----返回0
system("pause");
return 0;
}