字符串旋转判断

📅 2026/7/12 18:19:47
字符串旋转判断
字符串旋转判断 — 完整知识总结判断一个字符串是否为另一个字符串旋转之后的字符串巧妙运用strstr一招制胜。一、问题描述给定两个字符串s1和s2判断s2是否为s1旋转之后的字符串。示例s1s2结果说明AABCDBCDAA✅ 是左旋2个字符abcdACBD❌ 不是字符顺序不对旋转说明以AABCD为例AABCD 左旋一个字符 → ABCDA AABCD 左旋两个字符 → BCDAA AABCD 右旋一个字符 → DAABC二、核心解决方案方法一暴力法逐一旋转比较思路获取两个字符串长度长度不同直接返回0依次左旋s10 到len-1个字符每次旋转后与s2比较相同则返回1所有旋转都不匹配则返回0#define_CRT_SECURE_NO_WARNINGS#includestdio.h#includestring.h#defineMAX30inti0;// 左旋字符串 k 个字符voidleft_rotate(char*str,intk){intlenstrlen(str);k%len;/*比如k5len4,k%len,k1(左旋5个字符左旋一个字符)*/for(inti0;ik;i)//k觉得了旋转字符的个数若是两个字符就旋转两次一次一个字符{chartempstr[0];//储存第一字符//把除了第一个字符以为的其他字符往前移for(intj0;jlen-1;j){str[j]str[j1];}str[len-1]temp;}}// 判断 s2 是否是 s1 旋转后的字符串intis_rotation(char*s1,char*s2){intlen1strlen(s1);intlen2strlen(s2);// 长度不同不可能是旋转if(len1!len2){return0;}// 逐一尝试左旋 0 到 len-1 个字符for(i0;ilen1;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 法⭐ 推荐核心原理如果s2是s1旋转得到的那么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实际判断时不区分方向直接用strstr在s1 s1中查找即可左旋右旋都能覆盖需要区分方向逐一尝试左旋/右旋 k 个字符或利用公式右旋k 左旋(len-k)五、完整代码实现#includestdio.h#includestring.h#defineMAX30/** * 判断 s2 是否是 s1 旋转后的字符串 * 返回值 * -1不是旋转 * 0旋转的次数 */introtation_count(char*s1,char*s2){intlen1strlen(s1);intlen2strlen(s2);if(len1!len2){return-1;}if(len10){return0;}// 拼接 s1 s1chartemp[200];strcpy(temp,s1);strcat(temp,s1);// ★ 用 strstr 找到 s2 在 temp 中的位置char*posstrstr(temp,s2);if(posNULL)//当在temp找不到s2就等于空指针return-1;// 不是旋转// ★ 旋转次数 找到的位置索引intcountpos-temp;//s2在temp出现的起始地址减去temp的起始地址旋转次数returncount;}intmain(){chars1[MAX];chars2[MAX];printf(请输入同样长度的字符串\n);printf(第一个字符串s1:\n);scanf(%s,s1);printf(第一个字符串s2:\n);scanf(%s,s2);intcountrotation_count(s1,s2);if(count0){printf(%s 是 %s 旋转后的字符串\n,s2,s1);printf(旋转了 %d 个字符\n,count);}else{printf(%s 不是 %s 旋转后的字符串\n,s2,s1);}return0;}六、测试用例大全序号s1s2预期说明1AABCDBCDAA1左旋 2 个字符2abcdACBD0字符顺序不同不是旋转3AABCDABCDA1左旋 1 个字符4AABCDDAABC1右旋 1 个字符5hellohello1旋转 0 个两个相同6abcabcd0长度不同7abcbca1左旋 1 个8abccab1左旋 2 个9abccba0字符相同但顺序颠倒七、核心原理图解为什么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*len1大小写敏感strstr区分大小写ABC≠abc方向无关该方法不区分左旋还是右旋十、总结方面要点核心思想旋转字符串一定是s1 s1的子串关键函数strstr查找子串方向问题不区分左旋右旋全部覆盖⚡一句话总结把s1拼成两倍用strstr找s2找到就是旋转谢谢大家的赞赞