一天一大 lee(重复的子字符串)难度:简单-Day20200823

20200823

题目:

给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过 10000。

示例

  1. 示例 1:
输入: "abab"

输出: True

解释: 可由子字符串 "ab" 重复两次构成。
  1. 示例 2:
输入: [1, 2, 1, 2]
输出: False
  1. 示例 3:
输入: "abcabcabcabc"

输出: True

解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)

抛砖引玉

抛砖引玉

暴力校验

思路
从开始枚举字符串片段假设其满足,继续向后枚举校验,检验完成未遇到不满足则返回 true,不然返回 false

abcabc
ii+1i+2i+3i+4i+5
-jj+1j+2j+3j+4
jj+1j+2

前置条件:指定相同量字符之间的长度应该满足被 n 整除

/**
 * @param {string} s
 * @return {boolean}
 */
var repeatedSubstringPattern = function (s) {
  let len = s.length
  for (let i = 1; i * 2 <= len; ++i) {
    if (len % i == 0) {
      let match = true
      for (let j = i; j < len; ++j) {
        if (s[j] != s[j - i]) {
          match = false
          break
        }
      }
      if (match) {
        return true
      }
    }
  }
  return false
}

字符串匹配

字符串拼接一次自身,然后删除拼接后的字符串的开始和结束:

  • 如果字符串满足可以被子集重复得到,那么至少当前处理过的字符还包含原字符串 s
/**
 * @param {string} s
 * @return {boolean}
 */
var repeatedSubstringPattern = function (s) {
  return (s + s).slice(1, -1).includes(s)
}

正则

一般字符串匹配的问题都可以通过正则处理:

  • 匹配一个字符串组 w+,匹配其大于 1 次
/**
 * @param {string} s
 * @return {boolean}
 */
var repeatedSubstringPattern = function (s) {
  return /^(\w+)\1+$/.test(s)
}

KMP 算法

逻辑

  • KMP 算法分为模式串和匹配串
  • 先遍历模式串,记录模式串中,每个指针前的最长公共前缀
    • 当模式串与匹配串匹配时,某个位置不匹配时,
    • 直接将模式串的后移该指针位置的公共前缀的长度在再与匹配串该位置比较
    • 模式串已匹配的前缀字符无需再次匹配
/**
 * @param {string} s
 * @return {boolean}
*/
var repeatedSubstringPattern = function (s) {
  function kmp(query, pattern) {
    let n = query.length,
      m = pattern.length,
      fail = Array(m).fill(-1)
    // 最长公共前缀,不存在公共前缀填充-1
    for (let i = 1; i < m; ++i) {
      let j = fail[i - 1]
      while (j != -1 && pattern[j + 1] != pattern[i]) {
        j = fail[j]
      }
      if (pattern[j + 1] == pattern[i]) {
        fail[i] = j + 1
      }
    }
    // 校验  match记录匹配的位置
    let match = -1
    for (let i = 1; i < n - 1; ++i) {
      // 如果当前不匹配匹配,指针跳跃到前缀位置开始匹配
      while (match != -1 && pattern[match + 1] != query[i]) {
        match = fail[match]
      }
      // 如果当前位匹配,逐个向后匹配,知道模式串匹配完成
      if (pattern[match + 1] == query[i]) {
        ++match
        if (match == m - 1) {
          return true
        }
      }
    }
    // 与字符串方法类似,拼接两个s,且将单个s作为模式串匹配去掉首尾字符非拼接串
    return kmp(s + s, s)
  }
}

博客: 小书童博客

每天的每日一题,写的题解会同步更新到公众号一天一大 lee 栏目
欢迎关注留言

公号: 坑人的小书童

坑人的小书童

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值