字符串旋转判断

字符串旋转判断

字符串旋转判断 — 完整知识总结

判断一个字符串是否为另一个字符串旋转之后的字符串,巧妙运用strstr一招制胜。


一、问题描述

给定两个字符串s1s2,判断s2是否为s1旋转之后的字符串。

示例:

s1s2结果说明
"AABCD""BCDAA"✅ 是左旋2个字符
"abcd""ACBD"❌ 不是字符顺序不对

旋转说明(以"AABCD"为例):

AABCD 左旋一个字符 → ABCDA AABCD 左旋两个字符 → BCDAA AABCD 右旋一个字符 → DAABC

二、核心解决方案

方法一:暴力法(逐一旋转比较)

思路

  1. 获取两个字符串长度,长度不同直接返回0
  2. 依次左旋s10 到len-1个字符
  3. 每次旋转后与s2比较,相同则返回1
  4. 所有旋转都不匹配则返回0
#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#defineMAX30inti=0;// 左旋字符串 k 个字符voidleft_rotate(char*str,intk){intlen=strlen(str);k%=len;/*比如k=5,len=4,k%len,k=1(左旋5个字符=左旋一个字符)*/for(inti=0;i<k;i++)//k觉得了旋转字符的个数(若是两个字符,就旋转两次,一次一个字符){chartemp=str[0];//储存第一字符//把除了第一个字符以为的其他字符往前移for(intj=0;j<len-1;j++){str[j]=str[j+1];}str[len-1]=temp;}}// 判断 s2 是否是 s1 旋转后的字符串intis_rotation(char*s1,char*s2){intlen1=strlen(s1);intlen2=strlen(s2);// 长度不同,不可能是旋转if(len1!=len2){return0;}// 逐一尝试左旋 0 到 len-1 个字符for(i=0;i<len1;i++)//i决定了字符旋转个数{chartemp[100];strcpy(temp,s1);//把temp内容改成s1left_rotate(temp,i);//传参旋转if(strcmp(temp,s2)==0)//和s2比较,==0表示temp和s2相等{return1;}}return0;//若尝试了len-1个字符后还是不相等,返回假}intmain(){chars1[MAX];chars2[MAX];printf("请输入同样长度的字符串\n");printf("第一个字符串s1:\n");scanf("%s",s1);printf("第一个字符串s2:\n");scanf("%s",s2);if(is_rotation(s1,s2)){printf("%s 是 %s 旋转后的字符串,旋转个数:%d\n",s2,s1,i);}else{printf("%s 不是 %s 旋转后的字符串\n",s2,s1);}return0;}

按理来说k %= len是没必要的,因为k的范围以控制在0~len-1的范围了,改代码只是为了程序的安全性,即使有人乱传参也不影响。


方法二:拼接 + strstr 法(⭐ 推荐)

核心原理

如果s2s1旋转得到的,那么s2一定是s1 + s1的子串

数学本质

s1 = "abc" s1 + s1 = "abcabc" 所有旋转结果都在 "abcabc" 中: "abc"(旋转0个)→ 位置 0 "bca"(旋转1个)→ 位置 1 "cab"(旋转2个)→ 位置 2

算法步骤

① 判断两个字符串长度是否相等 → 不等则返回 0 ② 处理空字符串特殊情况 ③ 创建临时字符串 temp = s1 + s1 ④ 用 strstr 在 temp 中查找 s2 ⑤ 找到返回 1,否则返回 0

三、关键函数详解

1.strlen— 获取字符串长度

size_tstrlen(constchar*str);
  • 功能:计算字符串长度(不包括\0
  • 返回值:字符串中字符的个数

2.strcpy— 复制字符串

char*strcpy(char*dest,constchar*src);
  • 功能:将src的内容复制到dest
  • 返回值dest的指针

3.strcat— 拼接字符串

char*strcat(char*dest,constchar*src);
  • 功能:将src追加到dest末尾
  • 返回值dest的指针

4.strstr— 查找子串

char*strstr(constchar*haystack,constchar*needle);
  • 功能:在haystack中查找needle首次出现的位置
  • 返回值:找到 → 返回首位置指针;没找到 → 返回NULL

四、左旋与右旋的关系

核心规律

右旋 k 个字符 = 左旋 (len - k) 个字符

示例s1 = "AABCD",长度 = 5):

左旋等价右旋结果
左旋 0 个右旋 0 个AABCD
左旋 1 个右旋 4 个ABCDA
左旋 2 个右旋 3 个BCDAA
左旋 3 个右旋 2 个CDAAB
左旋 4 个右旋 1 个DAABC

实际判断时

  • 不区分方向:直接用strstrs1 + s1中查找即可,左旋右旋都能覆盖
  • 需要区分方向:逐一尝试左旋/右旋 k 个字符,或利用公式右旋k = 左旋(len-k)

五、完整代码实现

#include<stdio.h>#include<string.h>#defineMAX30/** * 判断 s2 是否是 s1 旋转后的字符串 * 返回值: * -1:不是旋转 * >=0:旋转的次数 */introtation_count(char*s1,char*s2){intlen1=strlen(s1);intlen2=strlen(s2);if(len1!=len2){return-1;}if(len1==0){return0;}// 拼接 s1 + s1chartemp[200];strcpy(temp,s1);strcat(temp,s1);// ★ 用 strstr 找到 s2 在 temp 中的位置char*pos=strstr(temp,s2);if(pos==NULL)//当在temp找不到s2就等于空指针return-1;// 不是旋转// ★ 旋转次数 = 找到的位置索引intcount=pos-temp;//s2在temp出现的起始地址减去temp的起始地址=旋转次数returncount;}intmain(){chars1[MAX];chars2[MAX];printf("请输入同样长度的字符串\n");printf("第一个字符串s1:\n");scanf("%s",s1);printf("第一个字符串s2:\n");scanf("%s",s2);intcount=rotation_count(s1,s2);if(count>=0){printf("%s 是 %s 旋转后的字符串\n",s2,s1);printf("旋转了 %d 个字符\n",count);}else{printf("%s 不是 %s 旋转后的字符串\n",s2,s1);}return0;}

六、测试用例大全

序号s1s2预期说明
1"AABCD""BCDAA"1左旋 2 个字符
2"abcd""ACBD"0字符顺序不同,不是旋转
3"AABCD""ABCDA"1左旋 1 个字符
4"AABCD""DAABC"1右旋 1 个字符
5"hello""hello"1旋转 0 个(两个相同)
6"abc""abcd"0长度不同
7"abc""bca"1左旋 1 个
8"abc""cab"1左旋 2 个
9"abc""cba"0字符相同但顺序颠倒

七、核心原理图解

为什么s1 + s1包含所有旋转?

s1 = "ABCD"为例:

所有可能的旋转: ABCD(旋转 0 个)、BCDA(旋转 1 个) CDAB(旋转 2 个)、DABC(旋转 3 个) s1 + s1 = "ABCDABCD" 从索引 0 开始 → 取 4 个字符 → "ABCD" ✅ 从索引 1 开始 → 取 4 个字符 → "BCDA" ✅ 从索引 2 开始 → 取 4 个字符 → "CDAB" ✅ 从索引 3 开始 → 取 4 个字符 → "DABC" ✅

🎯结论:所有旋转结果都是s1 + s1中长度为len的连续子串。


八、函数调用流程图

main() ├── is_rotation("AABCD", "BCDAA") │ ├── strlen(s1) → 获取长度 5 │ ├── strlen(s2) → 获取长度 5(相等,继续) │ ├── strcpy(temp, s1) → temp = "AABCD" │ ├── strcat(temp, s1) → temp = "AABCDAABCD" │ └── strstr(temp, s2) → 找到,返回指针 │ └── return 1 │ └── is_rotation("abcd", "ACBD") ├── strlen(s1) → 4 ├── strlen(s2) → 4(相等,继续) ├── strcpy(temp, s1) → temp = "abcd" ├── strcat(temp, s1) → temp = "abcdabcd" └── strstr(temp, s2) → 未找到,返回 NULL └── return 0

九、注意事项

注意事项说明
长度检查必须先检查,长度不同直接返回 0
空字符串两个空字符串互为旋转
内存安全temp数组要足够大(至少2*len+1
大小写敏感strstr区分大小写,"ABC""abc"
方向无关该方法不区分左旋还是右旋

十、总结

方面要点
核心思想旋转字符串一定是s1 + s1的子串
关键函数strstr查找子串
方向问题不区分左旋右旋,全部覆盖

一句话总结:把s1拼成两倍,用strstrs2,找到就是旋转!

谢谢大家的赞赞