返回

掌握双指针技巧,解锁 LeetCode 之无重复字符的最长字符串

前端

引言

在竞技编程和面试场景中,LeetCode 已成为一道绕不开的坎。解决 LeetCode 问题不仅可以检验你的编程能力,还能让你接触到各种算法和数据结构的实际应用。其中,双指针技巧是 LeetCode 中的常见套路,掌握它能有效地解决许多看似棘手的问题。今天,我们将以一道 Leetcode 经典题目——无重复字符的最长字符串,来深入解析双指针的精髓。

问题

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

思路分析

乍一看,这道题似乎需要使用蛮力法,遍历字符串中的所有子串并检查它们是否不包含重复字符。然而,这样做的时间复杂度为 O(n^2),对于大规模数据来说过于耗时。

因此,我们需要考虑更有效的方法。双指针技巧便是一种可行的方案。双指针法通过使用两个指针在字符串中移动来寻找解决方案。

双指针解法

在双指针解法中,我们使用两个指针 left 和 right 来定义子串的范围。初始时,left 和 right 都指向字符串的开头。我们不断移动 right 指针向右,同时检查子串是否包含重复字符。如果包含,则移动 left 指针向右,直到子串中不再包含重复字符。

具体实现如下:

  1. 初始化 left 和 right 指针,指向字符串的开头。
  2. 移动 right 指针向右,直到找到一个重复的字符。
  3. 如果找到重复字符,移动 left 指针向右,直到子串中不再包含重复字符。
  4. 更新最长子串的长度。
  5. 重复步骤 2-4,直到 right 指针到达字符串的末尾。

代码实现

def length_of_longest_substring(s):
    # 记录字符最后出现的位置
    char_index = {}
    # 初始化双指针
    left = right = max_length = 0

    while right < len(s):
        # 如果字符已出现过,更新 left 指针
        if s[right] in char_index and char_index[s[right]] >= left:
            left = char_index[s[right]] + 1
        # 更新字符最后出现的位置
        char_index[s[right]] = right
        # 更新最长子串长度
        max_length = max(max_length, right - left + 1)
        # 移动 right 指针
        right += 1

    return max_length

优化

上述解法的时间复杂度为 O(n),其中 n 为字符串的长度。为了进一步优化,我们可以使用滑动窗口优化技术。滑动窗口优化通过维护一个窗口,窗口内的字符不包含重复字符,随着 right 指针向右移动,窗口不断滑动。

滑动窗口解法

def length_of_longest_substring(s):
    # 记录字符最后出现的位置
    char_index = {}
    # 初始化双指针和窗口大小
    left = right = 0
    max_length = 0

    while right < len(s):
        # 如果字符已出现过,缩小窗口
        if s[right] in char_index:
            left = max(left, char_index[s[right]] + 1)
        # 更新字符最后出现的位置
        char_index[s[right]] = right
        # 更新窗口大小
        max_length = max(max_length, right - left + 1)
        # 移动 right 指针
        right += 1

    return max_length

结语

双指针技巧在 LeetCode 中广泛应用,通过巧妙地利用两个指针,我们可以有效地解决许多问题。无重复字符的最长字符串问题是一个经典的双指针问题,通过掌握双指针的精髓,我们不仅可以轻松解决这道题,还能为解决更多复杂问题打下坚实的基础。

拓展阅读

SEO 优化