[ 双指针、KMP ]796. 旋转字符串

139 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情

每日刷题 2021.04.07

题目

  • 给定两个字符串, s 和 goal。如果在若干次旋转操作之后,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
  • s 和 goal 由小写英文字母组成

解题思路

  • 首先:想到的是双指针做法
  • 其次又想到了字符串方法slice()
  • 虽然两个做法不同,但是思路是一样的。既然goal是通过s旋转得来的,那么只要在goal中找到s的开头,下标记为index。从index开始截取到goal的末尾,再从goal的开头截取到index - 1,将两段字符串进行拼接,如果能够组成s那么就返回true,否则返回false
  • 注意⚠️:如果只是用s开头的一个字母作为基准,那么在goal中可能存在多个相似的,因此需要将每一个都试一遍。如果遇到可以匹配成功的,那么就返回true;如果所有的情况都遍历完,没有符合的就返回false

学习题解(妙啊)

  • 两个字符串s相加,那么(s + s).container(goal)

回顾kMP算法

  • KMP本质是:优化常规做法中,每次都从头比较匹配串的操作。如何快速在原串中找到匹配字符串的下标。
  • kmp因为在非完全匹配的过程中(即:失败的匹配过程中),提取有效信息进行复用,以此来减少重复的匹配操作,优化时间复杂度。
  • kmp核心思想:不相等时,回退。
  • 主要分为2部分:
    • 匹配串的next数组
    • 原串和匹配串的匹配过程
  • 第一部分:next数组
    • 匹配串和自身进行匹配,所形成的数组。
    • 首先我们要明白两个概念:前缀:一个字符串中不包含最后一个元素的连续的子串;后缀:一个字符串中不包含最开始一个元素的连续的子串
      • 举例:字符串:bkdjsbk,其前缀[b,bk,bkd,bkdj,bkdjs,bkdjsb];后缀:[k,bk,sbk,jsbk,djsbk,kdjsbk]。比较前缀集合和后缀集合,从中找到相等的最长的子串bk
    • 现在我们知道了最长相等前缀是什么含义后。
  • 第二部分:原串和匹配串的匹配过程
    • 方法与求解next数组的方法相似

AC代码

var rotateString = function(s, goal) {
  // 旋转字符串:双指针可以呀
  // 所有相同的开头可以查一下
  let len = s.length;
  function isVerse(l) {
    // 当前给的l就是第一个匹配成功的字符
    // 拼接字符串
    let str = goal.slice(l) + goal.slice(0,l)
    if(str === s) return true;
    return false;
  }
  for(let i = 0; i < len; i++) {
    if(goal[i] == s[0]){
      if(isVerse(i)) return true;
    }
  }
  return false;
};

总结

  • 本题也可以使用kmp算法