开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情
前言
本文是关于刷题——判断旋转字符串的C语言实现。
新手一个,水平比较低,还请包涵。
判断旋转字符串
题目描述
写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。
例如:给定s1 = AABCD和s2 = BCDAA,返回1
给定s1 = abcd和s2 = ACBD,返回0
AABCD左旋一个字符得到ABCDA
AABCD左旋两个字符得到BCDAA
AABCD右旋一个字符得到DAABC
思路分析
双指针移位法
设定两个指针,一个头指针str_head,一个尾指针str_end,
左旋时:把str_head指向的值丢到临时变量tmp去,然后第一个往后的字符串整体左移一位,再把tmp的值放到str_end指向的位置;
右旋时:把str_end指向的值丢到临时变量tmp去,然后第一个往后的字符串整体左移一位,再把tmp的值放到str_head指向的位置。
单字符旋转判断
写一个判断函数JugRota(),其中调用一个旋转字符串函数RotaStr(),RotaStr()既可以左旋又可以右旋字符串,用的是双指针移位法。
输入两个字符串str和_str,判断第一个是不是第二个旋转之后得到的,在JugRota()中把第二个字符串放入一个临时字符数组tmp中,先判断是否相同,再判断是否是左旋得到的,再判断是否是右旋得到的,都不是的话就是不能旋转得到的。
判断左右旋的方法是把tmp中字符串左旋或右旋后马上和str字符串比较看看是否相同,不是的话继续旋转,这里设置次数为sz/2,sz是字符串长度。
为什么次数这样设置呢?
其实在思考过程中会发现左旋和右旋其实是互为逆过程的,这样的话左旋得到的总可以使用右旋得到,比如ABBCD左旋一个字符得到BBCDA,而BBCDA又可以由ABBCD右旋四个字符得到,那怎么区分左右旋呢?我这里就以中间为界限,每次判断时最多左旋或者右旋sz/2次,如果还不相同就表示是不由该旋转方向得到的。
代码实现
//旋转字符串的函数,每次调用只旋转一次
void RotaStr(char *str, char dir)
{
int i = 0;
int j = 0;
char tmp = 0;
int sz = strlen(str);
char* str_head = str;//头指针
char* str_end = str + sz - 1;//尾指针
if ('L' == dir)//左旋
{
tmp = *str_head;
for (j = 0; j < sz - 1; j++)
{
*(str + j) = *(str + j + 1);
}
*str_end = tmp;
}
else if ('R' == dir)//右旋
{
tmp = *str_end;
for (j = 0; j < sz - 1; j++)
{
*(str_end - j) = *(str_end - j - 1);
}
*str_head = tmp;
}
else
{
printf("旋向输入有误!\n");
}
}
int JugRota(char *str, char *_str, int sz)
{
int i = 0;
//用临时字符数组替代_str进行旋转
char tmp[20] = {0};
strcpy(tmp, _str);
//判断是否相同
if (!strcmp(str, tmp))
return -1;
//判断是否是左旋得到
for (i = 0; i < sz / 2; i++)
{
RotaStr(tmp, 'L');
if (!strcmp(str, tmp))
return 1;
}
strcpy(tmp, _str);//刷新临时字符数组
//判断是否是右旋得到
for (i = 0; i < sz / 2; i++)
{
RotaStr(tmp, 'R');
if (!strcmp(str, tmp))
return 0;
}
//都不是的话就是不能旋转得到
return -2;
}
int main()
{
char str[20] = { 0 };
char _str[20] = { 0 };
printf("请分别输入要判断的两串字符串:\n");
scanf("%s %s", str, _str);
if (1 == JugRota(str, _str, strlen(str)))
{
printf("第一串字符串是由第二串字符串左旋得到的!\n");
}
else if(0 == JugRota(str, _str, strlen(str)))
{
printf("第一串字符串是由第二串字符串右旋得到的!\n");
}
else if(-1 == JugRota(str, _str, strlen(str)))
{
printf("第一串字符串与第二串字符串相同!\n");
}
else
{
printf("第一串字符串与第二串字符串不存在旋转互化关系!\n");
}
return 0;
}
更简便的做法
实际上该题只要求判断是不是旋转得到的而没有特意区分左右旋,同时左右旋可能等效,所以只考虑旋转的话这题有一个很简单的做法:
其实ABCDE无论怎么旋,旋转后的所有结果,都包含在了ABCDEABCD这个字符串里了。
所以做法很简单,只需要将原字符串再来一遍接在后面,然后找一找待查找的字符串是不是两倍原字符串的子集即可。
主要用到几个库函数,同时要注意先判断两字符串长度相不相等。
int JugRota(const char * src, char * find)
{
if(strlen(src) != strlen(find))
return 0;
char tmp[256] = { 0 }; //用一个辅助空间将原字符串做成两倍原字符串
strcpy(tmp, src); //先拷贝一遍
strcat(tmp, src); //再连接一遍
return strstr(tmp, find) != NULL; //看看找不找得到
}