【力扣每日一题】796.旋转字符串

题目描述

给定两个字符串, sgoal。如果在若干次旋转操作之后,s 能变成 goal ,那么返回 true

s旋转操作 就是将 s 最左边的字符移动到最右边。

  • 例如, 若 s = 'abcde',在旋转一次之后结果就是'bcdea'

示例 1:

输入: s = "abcde", goal = "cdeab"
输出: true

示例 2:

输入: s = "abcde", goal = "abced"
输出: false

提示:

  • 1 <= s.length, goal.length <= 100
  • sgoal 由小写英文字母组成
想法

这题简单啊,不就不直接模拟吗?等等,先看一下会不会超时,哦,长度都在100以内,那没事了。搞起来!(java的StringBuffer不太熟悉,先用python试试)

class Solution:
    def rotateString(self, s: str, goal: str) -> bool:
        sLs = list(s) # 字符串转换成列表,便于操作
        for i in range(len(sLs)-1): # n-1轮,每一轮移除第一个字符,然后加到末尾
            a = sLs[0]
            sLs.remove(sLs[0])
            sLs.append(a)
            if "".join(sLs)==goal: # 将列表中的元素合成字符串,判断一下是否与goal相同
                return True
        return False

提交,过了!

托这次规模比较小的福,用时28ms,打败了96%的人!(可能也没多少人用python写。。。)


但,应该还有更加智慧的解法!

于是我去看了一下官方。

哦,原来s和goal的长度还可以不一样啊。。。

官方

(方法一不赘述,本质上还是匹配字符串,只是写得比较高级,用了循环队列的mod运算)

方法二:搜索子字符串

首先,如果 s 和 goal 的长度不一样,那么无论怎么旋转,s 都不能得到 goal,返回 false。字符串 s + s 包含了所有 s 可以通过旋转操作得到的字符串,只需要检查 goal 是否为 s + s 的子字符串即可。

这里用到了一个很巧妙的思路,将s所有旋转可能得到的字符串都包含在了一个更大的字符串里,即s+s,这样j就省去了每次变换s的操作。

class Solution{
    public boolean rotateString(String s,String goal){
        //先判断s和goal的长度是否相等,再判断s+s中是否包含goal
        return s.length()==goal.length() && (s+s).contains(goal);
    }
}

今天主要还是学习了这个contains()函数的用法,有些库函数确实有必要去学习记忆,无需所有功能都自己去手写实现。


后记:
不过官方(还有很多大佬)是如何想到这个s+s字符串的呢?为什么我只想到了简单的模拟,而没有跳到更高一层去看待这个问题呢?
一方面是由于我的经验没有那些大佬丰富,没有太多这种数据的直觉
官方出题自然是按照自己的套路出,为了体现一种想法而特意设计的一个题目
但我们还是得来看看这里面的思维过程,如何从简单的模拟跳到高层次的更大的字符串:
首先我们如果在脑子中模拟的话,会发现,一个 长度为n的字符串s,如果一直在旋转(将首字符移到末尾),那么经过n次,必然会恢复成原来的字符串,也就是说,我们其实只要进行n-1次旋转,即可遍历s的所有状态,这是模拟的思路。
那么,如果我们把字符串想象在一个模具里,每次旋转都是将第一个字符拿到最后的位置,则容易发现,这个模具如果想表示字符串的所有状态,那么它最短的长度就是2n,也即s+s,这里面可能涉及到了函数里的最小正周期的概念。
但最重要的,我们首先得要有这样一种思想 :将所有有限的可能性都包含在一个可操作的区域内, 这样第二种解法的萌芽才会在脑海中生根。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值