字符串轮转

标签: 字符串 字符串匹配

难度: Easy

字符串轮转。给定两个字符串s1s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottleerbottlewat旋转后的字符串)。

示例1:

 输入:s1 = "waterbottle", s2 = "erbottlewat"
 输出:True

示例2:

 输入:s1 = "aa", s2 = "aba"
 输出:False

提示:

  1. 字符串长度在[0, 100000]范围内。

说明:

  1. 你能只调用一次检查子串的方法吗?

Submission

运行时间: 19 ms

内存: 16.3 MB

class Solution:
    def isFlipedString(self, s1: str, s2: str) -> bool:
        return len(s1) == len(s2) and s1 in (s2 + s2)

Explain

解题思路是基于一个简单的观察:如果字符串s2是字符串s1的一个轮转,那么s2必然是由s1两部分的某种组合(前半段和后半段)构成的。因此,如果我们将s1与自身拼接,形成新字符串s1s1,那么s2必须是s1s1的一个子字符串。这种方法首先检查两个字符串长度是否相等,若不相等,则s2不可能是s1的轮转。如果长度相等,再检查s2是否为s1s1的子串。

时间复杂度: O(n)

空间复杂度: O(n)

# 定义Solution类

class Solution:
    def isFlipedString(self, s1: str, s2: str) -> bool:
        # 首先检查两个字符串的长度是否相等
        if len(s1) != len(s2):
            return False
        # 将s1与自身连接,并检查s2是否为结果字符串的子串
        return s2 in (s2 + s2)

Explore

假设s1是'abcde',任意的轮转可以看作是将s1从某个点断开成为两个部分,然后交换这两部分的位置。例如,如果我们将'abcde'在c处断开,得到'abc'和'de',然后交换这两部分的位置,得到'deabc',这就是一个轮转。如果我们将s1与自身拼接,得到'abcdeabcde',无论原字符串s1如何断开和重组,得到的轮转结果都会作为这个新字符串的一个子串出现。这是因为拼接后的字符串包含了s1所有可能的轮转组合。

检查s1和s2的长度是否相等是必要的初步步骤,因为只有长度相等的字符串才可能是彼此的轮转。然而,仅仅长度相等并不能保证s2就一定是s1的轮转。例如,s1='abcde'和s2='eabcd'长度相同,并且s2是s1的轮转;而s1='abcde'和s2='edcba'虽然长度相同,但s2不是s1的轮转。所以,长度检查后,还需要进一步验证s2是否为s1s1的子字符串来确保s2确实是s1的轮转。

确实,这里有一个笔误。正确的表达应该是检查s2是否为新字符串`(s1 + s1)`的子串。代码应改为`return s2 in (s1 + s1)`。这个表达式正确地将s1与自己拼接,并检查s2是否为这个新字符串的子串,从而验证s2是否是s1的轮转。