
本文详解如何在Java中正确判断一个字符串是否可通过旋转(左移字符)得到另一字符串,重点纠正常见的==误用问题,并提供高效、安全的StringBuilder与String比较方案。
本文详解如何在java中正确判断一个字符串是否可通过旋转(左移字符)得到另一字符串,重点纠正常见的`==`误用问题,并提供高效、安全的`stringbuilder`与`string`比较方案。
在字符串处理中,判断“旋转等价性”(如 "abcd" 是否可经若干次左旋变为 "cdab")是一个典型场景。其核心逻辑是:对源字符串 s 执行最多 n−1 次左旋(n = s.length()),每次将首字符移至末尾,检查是否与目标字符串 goal 相等。
然而,初学者常陷入一个关键陷阱:使用 == 比较 StringBuilder.toString() 与 String。如原代码所示:
if (builder.toString() == goal) { ... } // ❌ 错误!比较的是对象引用
== 在Java中仅比较两个引用是否指向同一内存地址,而 builder.toString() 每次调用都会创建新的 String 对象(即使内容相同),因此即使语义相等,== 也几乎总是返回 false。这是本例中 flag 始终为 false 的根本原因。
✅ 正确做法是使用 equals() 方法进行内容比对:
if (builder.toString().equals(goal)) { ... } // ✅ 正确!比较字符串值
此外,该算法还可大幅优化。手动模拟旋转(嵌套循环移动字符)不仅代码冗长、易错,时间复杂度也达 O(n²)。更优雅的解法是利用字符串拼接特性:s 可旋转为 goal 当且仅当 goal 是 s + s 的子串,且二者长度相等。例如:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
s = "abcd"→s + s = "abcdabcd" -
goal = "cdab"→"cdab"确实出现在"abcdabcd"中 ✅ -
goal = "abced"→ 长度不等或非子串 ❌
推荐实现如下(简洁、高效、O(n) 时间):
public static boolean rotateString(String s, String goal) {
// 长度不同直接排除
if (s.length() != goal.length()) return false;
// 利用双倍字符串检测旋转关系
return (s + s).contains(goal);
}
若必须使用 StringBuilder(如需复用缓冲区或避免临时字符串),也应始终通过 .toString().equals(...) 比较,而非 ==。同时注意:
- ✅
StringBuilder适合频繁修改场景(如循环中多次追加/反转),避免String不可变导致的对象爆炸; - ⚠️ 多线程环境下应改用线程安全的
StringBuffer; - ? 永远不要用
==比较字符串内容——这是Java入门必纠的核心误区。
总结:字符串旋转判定的本质是子串匹配问题;StringBuilder 是高效构建中间状态的工具,但其 toString() 结果仍需用 equals() 与 String 比较;理解 == 与 equals() 的语义差异,是写出健壮Java字符串代码的第一道门槛。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










