本篇总结了字符串旋转问题的几种解决方法,字符串左旋和右旋原理相同,会其一便可知其二,当然还有很多方法,我只列举相对容易理解的方法。
左旋转字符串
字符串旋转问题:字符串左旋
实现一个函数,可以左旋字符串中的k个字符。
例如:
ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB
方法1:暴力旋转法
每次让字符串旋转一个,然后让旋转几个就循环几次。
思路:
1.拿走第一个字符
2.让数组后面的字符往前覆盖
3.让最后一个元素放入第一个字符
#include <string.h>
void left_move(char arr[], int k)
{
int len = strlen(arr);
k %= len;//当字符旋转次数为自己长度时,字符旋转跟没有旋转一样,(也就旋转回来了)
//所以超过自身次数旋转跟某次旋转是一样的
//第一步拷贝拿走第一个字符
char tmp = arr[0];
//第二步,将后面的往前覆盖
int i;
for (i = 0; i < len - 1; i++)
{
arr[i] = arr[i + 1];
}
//第三步,将第一个字符放在最后面
arr[len - 1] = tmp;
}
int main()
{
char arr[] = "ABCD";
int k;
scanf("%d", &k);
left_move(arr, k);
printf("%s", arr);
return 0;
}
方法2:空间辅助法
借助一个数组让它帮忙先放下不着急旋转的字符串,然后再将要旋转的字符放在后面,最后再拷贝回来
思路:
1.创建一个数组空间
2.将不旋转的字符串先放进去
3.将要旋转的字符放在后面
4.将数组拷贝回来
void left_move(char arr[],int k)
{ //1.创建一个空数组
char tmp[256] = { 0 };
//旋转k 这个点是一个断点k后面的是不旋转的字符串,前面是旋转的字符
//后面不旋转的拷贝到tmp中,
strcpy(tmp, arr + k);
//再将前面旋转的放进tmp后面
strncat(tmp, arr, k);// strncat功能: 将arr中k个字符追加到tmp后面
//再将tmp拷贝回去
strcpy(arr, tmp);
}
int main()
{
char arr[] = "abcdef";
int k;
scanf("%d", &k);
left_move(arr,k)
printf("%s", arr);
return 0;
}
方法3:三步翻转法
对于这个方法我们可以这样想:
将一个字符串分成两个部分,X和Y两个部分,在字符串上定义反转(逆序)的操作为
X^T, 即把X的所有字符全部反转(逆序)【比如X=“abcd”,全部反转为 “dcba”,所以X ^T=“dcba”】,那么我们可以得到下面的结论:
(X ^T Y ^T) ^T=YX.
所以显然就可以转换为字符串反转的问题了
思路也就是:
第一步逆序左边(k处为分界点)
第二步逆序右边
第三步逆序整体
void reverse(char *left,char*right)
{
//逆序函数需要两个指针分别指向前面和后面,当前面指针小于后面指针时
//说明还有元素需要逆序
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main()
{
char arr[] = "ABCD";
int len = strlen(arr);
int k=0;
scanf("%d", &k);
int k%=len;
//写一个逆序函数reserve
//先逆序左边
reverse(arr,arr+k-1);
//再逆序右边
reverse(arr + k, arr + len - 1);
//再整体逆序
reverse(arr, arr + len - 1);
printf("%s", arr);
return 0;
}
结果:
字符串旋转结果
写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。
例如:给定s1 =AABCD和s2 = BCDAA,返回1
给定s1=abcd和s2=ACBD,返回0.
AABCD左旋一个字符得到ABCDA
AABCD左旋两个字符得到BCDAA
AABCD右旋一个字符得到DAABC
这个也是字符串旋转问题,要求判断一个字符串是否是另外一个字符串旋转得到的
方法1:利用左旋字符串函数判断
思路:
我们可以利用上面的左旋字符的函数,让一个字符串每次旋转一次,每次旋转完后再与另外一个字符串比较,看是否相同。
当然有要注意的地方,当两个字符串长度都不一样大时,肯定不可能是旋转得到的。
#include <string.h>
void left_move(char arr[], int k)
{
int len = strlen(arr);
k %= len;//当字符旋转次数为自己长度时,字符旋转跟没有旋转一样,所以超过自身次数旋转跟某次旋转是一样的
//左旋字符串
//第一步拷贝拿走第一个字符
char tmp = arr[0];
//第二步,将后面的往前覆盖
int i;
for (i = 0; i < len - 1; i++)
{
arr[i] = arr[i + 1];
}
//第三步,将第一个字符放在最后面
arr[len - 1] = tmp;
}
int is_move(char arr1[], char arr2[])
{
int len1 = strlen(arr1);
int len2 = strlen(arr2);
if (len1 != len2)//判断一下长度是否相等,如果不等直接返回0
{
return 0;
}
int i;
for (i = 0; i < len1; i++)
{
left_move(arr1, 1);//每次左旋一个
if (strcmp(arr1, arr2) == 0)//每次旋转完与字符串2比较是否相同
{
return 1;
}
}
return 0;
}
int main()
{
char arr1[] = "ABCDEF";
char arr2[] = "CDEFAB";
int ret=is_move(arr1, arr2);
if (ret == 1)
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
方法2:空间辅助法
其实ABCDE无论怎么旋,旋转后的所有结果,都包含在了ABCDEABCD这个字符串里了。
所以做法很简单,只需要将原字符串再来一遍接在后面,然后找一找待查找的字符串是不是两倍原字符串的子集即可。
思路:
1.给字符串1自己追加一个自己字符串,然后拷贝到一个数组里
2.在追加后的字符串中找子符串中是否有与要比较的字符一样的
int is_move(char arr1[],char arr2[])
{
int len1 = strlen(arr1);
int len2 = strlen(arr2);
if (len1 != len2)//判断一下长度是否相等,如果不等直接返回0
{
return 0;
}
char tmp[256]={0};//用一个辅助空间将原字符串做成两倍原字符串
tmp=arr1;//将arr1中的内容拷贝到数组tmp中,因为tmp中空间足够大,可以给后面再追加len1个元素,因为arr1数组空间大小不知道,所有我们不能直接给arr1,追加自身字符。
strncat(tmp, arr1, len1);//给数组tmp追加一个arr1,追加6个元素
//strstr是用来查找字符串中的子串的,如果字符串中找到要比较的字符串
//那么将返回要比较的字符在该字符串中的地址
//如果没有则返回NULL.
if (strstr(tmp, arr2) != NULL)
return 1;
else
return 0;
}
int main()
{
char arr1[] = "ABCDEF";
char arr2[] = "CDEFAB";
int ret = is_move(arr1, arr2);
if (ret == 1)
{
printf("Yes\n");
}
else
{
printf("No\n");
}
return 0;
}
结果: