LeetCode.3-无重复字符的最长子串(Swift)

80 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情 。如果哪里写的不对,请大家评论批评。

希望往后的日子,可以每天坚持一个算法

之后的文章会按照XV小程序CodeTop的排行去刷,证明这些算法题都是在面试中经常见到的。 比如前面的 反转链表 热度排行第一。

无重复字符的最长子串

题目

给定一个字符串,找出不含有重复字符的最长子串的长度。

示例:

给定 “abcabcbb” ,没有重复字符的最长子串是 “abc” ,那么长度就是3。

给定 “bbbbb” ,最长的子串就是 “b” ,长度是1。

给定 “pwwkew” ,最长子串是 “wke” ,长度是3。请注意答案必须是一个子串,”pwke” 是 子序列 而不是子串。

分析

这个的考点主要是滑动窗口或者叫做动态规划,当然也可以使用双重循环来找到最大的值,显然不是要考我们双重循环。

滑动窗口

滑动窗口就是一个动态的窗口,这个窗口可以是固定长度,也可以是可变长度,下面我们使用图来解释一下滑动窗口和算法拆解

拆解一下我们需要的变量

  1. 需要一个字段来记录最大的长度MaxLen
  2. 需要一个字段来记录开始的位置start
  3. 需要一个哈希来记录数据是否存在,Swift我们可以用字典来做dic

图解

无重复字符的最长子串.drawio.png

  1. 遍历字符串的每一个数据,定义了start从0开始(也就是a),如果在哈希中不存在,标记上当前的位置,char为key,下标为value 。dic[char] = i
  2. 这个时候start下标为0,MaxLen = i -start + 1 = 1 无重复字符的最长子串.drawio (1).png
  3. i++之后,取值b,发现哈希不存在,继续上一步的操作,标记上当前的位置,char为key,下标为value 。dic[char] = i
  4. 这个时候start依旧下标0开始,MaxLen = i -start + 1 = 1 = 2

无重复字符的最长子串.drawio (2).png

  1. 再次i++,取值是a,这时发现哈希中已经存在a,这表示有重复的字符,那么我们要跳过a,从a的下一个字符作为起始点,start = dic[char] + 1,图中字段是随意定义的,理解为主。
  2. 下一步还需要把当前新的下标记录下来,需要会覆盖原来的值。
  3. 这时候start是从下标到了1的位置,MaxLen = i -start + 1 = 1 = 2这时候发现居然还是等于2,也就是说ab、ba都是2的长度,可以任意取值。为了保持MaxLen是最大值,我们一般用MaxLen = max(MaxLen, i - start + 1)
  4. 下面就是重复上面的方法,不再文字介绍了,直接看图吧

无重复字符的最长子串.drawio (3).png

代码

    func lengthOfLongestSubstring(_ s:String) -> Int {
        let list = Array(s)
        var dic = [Character:Int]()
        var MaxLen = 0
        var start = 0
        for (i,char) in list.enumerated() {
            if let index = dic[char] {
                start = max(start, index + 1)
            }
            MaxLen = max(MaxLen, i - start + 1)
            dic[char] = i
        }
        return MaxLen
    }
class Solution {
    func lengthOfLongestSubstring(_ s: String) -> Int {
         if s.count < 2 {  return s.count }
        let chs = Array<Character>(s)
        var map = Array(repeating: -1, count: 128)
        var maxLen = 0
        var start = 0
        for i in 0..<chs.count {
            let char = chs[i]
            let idx = Int(char.asciiValue ?? 0)

            let preIdx = map[idx] 
            start = max(start, preIdx + 1)   //"abba"的情况
            
            maxLen = max(maxLen, i-start+1)
            map[idx] = i
            //print("\(chs[0...i])的最长无重复子串长度是\(maxLen), start=\(start)")
        }
        return maxLen
    
    }
}