返回

剑指Offer 48:最长不含重复字符的子字符串解析

后端

一、问题

给定一个字符串,请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

二、解决方案

1. 动态规划

动态规划是一种常见的解决字符串问题的技术。其基本思想是将问题分解成更小的子问题,并使用递推关系来求解这些子问题,最终将这些子问题的解组合起来得到整个问题的解。

对于本问题,我们可以将字符串分解成由每个字符组成的子字符串。对于每个子字符串,我们可以计算出其最长不含重复字符的子字符串的长度。然后,我们就可以使用这些子问题的解来计算整个字符串最长不含重复字符的子字符串的长度。

2. 滑动窗口

滑动窗口是一种用于解决字符串问题的另一个常见技术。其基本思想是使用一个固定长度的窗口来扫描字符串,并不断更新窗口中的字符。当窗口中包含重复字符时,我们将窗口向右移动一个字符,并更新窗口中的字符。当窗口中不包含重复字符时,我们记录下窗口的长度,并继续扫描字符串。

对于本问题,我们可以使用一个长度为 k 的窗口来扫描字符串。k 是字符串中不包含重复字符的最长子字符串的长度。当窗口中包含重复字符时,我们将窗口向右移动一个字符,并更新窗口中的字符。当窗口中不包含重复字符时,我们记录下窗口的长度,并继续扫描字符串。

三、代码实现

1. 动态规划

def longest_substring_without_repeating_characters_dp(s):
    """
    动态规划求解最长不含重复字符的子字符串
    :param s: 输入字符串
    :return: 最长不含重复字符的子字符串的长度
    """
    n = len(s)
    dp = [[0] * n for _ in range(n)]
    max_len = 0
    for i in range(n):
        dp[i][i] = 1
        for j in range(i + 1, n):
            if s[j] not in s[i:j]:
                dp[i][j] = dp[i][j - 1] + 1
                max_len = max(max_len, dp[i][j])
    return max_len


**2. 滑动窗口** 

```python
def longest_substring_without_repeating_characters_sliding_window(s):
    """
    滑动窗口求解最长不含重复字符的子字符串
    :param s: 输入字符串
    :return: 最长不含重复字符的子字符串的长度
    """
    max_len = 0
    left = 0
    right = 0
    window = set()
    while right < len(s):
        if s[right] not in window:
            window.add(s[right])
            right += 1
            max_len = max(max_len, right - left)
        else:
            window.remove(s[left])
            left += 1
    return max_len

四、复杂度分析

1. 动态规划

动态规划的复杂度为 O(n^2), 其中 n 是字符串的长度。这是因为动态规划需要计算每个子字符串的最长不含重复字符的子字符串的长度,而每个子字符串的长度都为 n

2. 滑动窗口

滑动窗口的复杂度为 O(n), 其中 n 是字符串的长度。这是因为滑动窗口只需扫描字符串一遍,而每次扫描只需检查窗口中的字符是否重复。

五、总结

本篇博客提供了两种解决剑指Offer 48:最长不含重复字符的子字符串问题的方案,包括动态规划和滑动窗口。这两种方法都各有优缺点。动态规划的复杂度较高,但其代码实现较为简单。滑动窗口的复杂度较低,但其代码实现较为复杂。读者可以根据自己的需要选择合适的方法来解决此类问题。