LeetCode / Scala - 无重复字符最长子串 ,最长回文子串

简介: ​LeetCode 里有一类字符子串问题,这里主要分析无重复字符的最长子串与最长回文子串,总结相关方法。

一.引言

LeetCode 里有一类字符子串问题,这里主要分析无重复字符的最长子串最长回文子串,总结相关方法。

二.无重复字符最长子串

1.题目要求

image.gif编辑

给定字符串 s,要求找出字符内无重复的最长子串,注意是子串不是子序列。

2.滑动指针法

A.思路分析

通过 start 与 end 双指针指定最长子串范围,通过 HashMap 记录每一个 char 字符的索引并实现去重。

-> 遍历字符串所有 char 字符

-> 判断当前字符是否在 HashMap 中,并更新当前 start

-> end += 1,并记录当前 char 对应的索引

-> length = end - start,比较 length 与 maxLength 并更新最大长度

B.代码实现

def solution(s: String): Int = {
    // 双指针与索引Map
    var maxLength = 0
    var start = 0
    var end = 0
    val indexMap = mutable.HashMap[Char, Int]()
    // 转换为char
    val arr = s.toCharArray
    s.toCharArray.foreach(char => {
      if (indexMap.contains(char)) {
        start = math.max(indexMap(char), start) // 更新 start
      }
      end += 1 // 更新 end
      indexMap(char) = end
      maxLength = math.max(end - start, maxLength) // 更新 maxLength
      println(s"char: $char start: $start end: $end max: $maxLength arr: ${s.slice(start, end).mkString("")}")
    })
    maxLength
  }

image.gif

为了直观,我们加入了日志打印,以 s = "abba" 为例进行测试:

def main(args: Array[String]): Unit = {
    val s = "abba"
    println(solution(s))
  }

image.gif

可以结合执行过程理解双指针 start 和 end 的变化。

image.gif编辑

C.执行效率

image.gif编辑

时间复杂度 O(n),其中 n 为字符串的长度,即 char 的数量,空间复杂度为 O(|∑|),其中 ∑ 为当前字符串的去重集合,正常情况可以近似为 O(n),极端情况例如 s="11111" 则退化为 O(1)。

三.最长回文子串

1.题目要求

image.gif编辑

给定字符串 s,寻找其最长回文子串,这里解释下什么是回文串,即正反一样的字符串,例如 aabbaa,aba,ccccc 均为回文子串,注意最长无重复子串返回字符串长度而本例返回字符串。

2.中心扩展法

A.思路分析

首先清晰回文字符的转移条件,假设 P(i,j) 为回文子串,如果 i-1,j+1 对应位置元素相同,则 P(i-1, j+1) 也是回文子串,如此类推

-> 初始化 maxLeft,maxRight 记录最长回文串的区间,初始化 maxLength 记录最长长度

-> 遍历数组数组索引,向左侧探索,当前索引为 mid,则左侧为 mid - 1,如果 s(mid) = s(left) 则 P(left, mid) 构成回文子串,left -=1 继续向左探索

-> 向右侧探索,方法同上,right = mid + 1,判断 s(mid) 与 s(right)

-> 向两侧扩展,单向扩展主要寻找与 mid 元素相同的元素,例如 a -> aaa,双侧则主要是寻找两侧相同元素,例如 aaa -> baaab,判断 s(left) = s(right)

-> 更新 maxLeft,maxRight 记录当前最长回文串范围

B.代码实现

// 中心扩展算法
  def solution(s: String): String = {
    var length = 1
    // 从每个 mid 开始向两边扩散
    var maxLeft = 0 // 起点
    var maxRight = 0 // 终点
    var maxLength = 0 // 最长回文串长度
    val arr = s.toCharArray
    arr.indices.foreach(mid => {
      var left = mid - 1
      var right = mid + 1
      // 向左侧扩展
      while (left >= 0 && arr(left).equals(arr(mid))) {
        left -= 1
        length += 1
      }
      // 向右侧扩展
      while (right <= arr.length - 1 && arr(right) == arr(mid)) {
        right += 1
        length += 1
      }
      // 向两侧扩展
      while (left >= 0 && right <= arr.length - 1 && arr(left) == arr(right)) {
        left -= 1
        right += 1
        length += 2
      }
      // 更新
      if (length > maxLength) {
        maxLeft = left
        maxRight = right
        maxLength = length
      }
      length = 1
    })
    println(maxLeft, maxRight, maxLength)
    s.substring(maxLeft + 1, maxRight)
  }

image.gif

分别向左,右,两侧扩展,最后更新区间,可以参照上面思路分析,由于判断相等后,继续 left -= 1 寻找下一个 left,所以最后满足的左边界为 realLeft = maxLeft + 1,maxRight 同理,maxRight = realRight + 1,所以最终结果 subString(maxLeft + 1,maxRight)。

C.执行效率

image.gif编辑

欧了一把,不知道这次提交怎么跑这么快,算法时间复杂度 O(n^2),因为遍历 n 个字符,每个字符左右扩展,空间复杂度 O(1)。

四.总结

可以看到很多算法都使用了 双指针、HashMap,因此要理解它们常用的用法与边界条件,其次回文串由于 P(i,j) 向 P(i-1,j+1) 的转移状态,也适用于动态规划,后面有时间整理一下动态规划相关。

目录
相关文章
|
3月前
|
存储 算法 程序员
【Leetcode 程序员面试金典 01.01】判定字符是否唯一 —— 位运算|哈希表
可以使用哈希表或位运算来解决此问题:由题可知s[i]仅包含小写字母,int[26]即能表示字符的出现次数;
|
1月前
|
网络协议
《 LeetCode 热题 HOT 100》——无重复字符的最长子串
《 LeetCode 热题 HOT 100》——无重复字符的最长子串
|
2月前
|
存储 算法 Go
LeetCode第五题: 最长回文子串
给定一个字符串 `s`​,找到 `s`​ 中最长的回文子串。你可以假设 `s`​ 的最大长度为 1000。
LeetCode第五题: 最长回文子串
|
2月前
|
存储 算法 Go
LeetCode 第三题: 无重复字符的最长子串
  给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。
|
3月前
【Leetcode 2707】字符串中的额外字符 —— 动态规划
1. 状态定义:把`s[i−1]`当做是额外字符,`d[i] = d[i−1] + 1` 2. 状态转移方程:遍历所有的`j(j∈[0,i−1])`,如果子字符串`s[j...i−1]`存在于`dictionary`中,那么`d[i] = min d[j] 3. 初始状态`d[0] = 0`,最终答案为`d[n]`
|
27天前
|
机器学习/深度学习 算法
力扣刷题日常(一)
力扣刷题日常(一)
20 2
|
1月前
|
存储 索引
《LeetCode》—— LeetCode刷题日记
《LeetCode》—— LeetCode刷题日记
|
1月前
|
搜索推荐
《LeetCode》——LeetCode刷题日记3
《LeetCode》——LeetCode刷题日记3
|
1月前
|
容器
《LeetCode》——LeetCode刷题日记1
《LeetCode》——LeetCode刷题日记1

热门文章

最新文章