返回

如何找到字符串中的无重复字符最长子串:JS、TS和Python代码解析

前端

算法概述

无重复字符最长子串问题可以为:给定一个字符串,请找出其中不含有重复字符的最长子串。例如,对于字符串 "abcabcbb",无重复字符的最长子串是 "abc",其长度为 3;对于字符串 "bbbbbbb",无重复字符的最长子串是 "b",其长度为 1。

为了解决这个问题,我们可以使用滑动窗口算法。该算法的基本思想是使用两个指针来定义一个窗口,然后在字符串中移动窗口。窗口中的字符必须不重复,并且窗口的大小应该是最大的。

下面是滑动窗口算法的具体步骤:

  1. 初始化两个指针,分别指向字符串的开始和结束。
  2. 在窗口中查找重复字符。
  3. 如果窗口中存在重复字符,则将开始指针向右移动一个字符,然后重复步骤2。
  4. 如果窗口中不存在重复字符,则将结束指针向右移动一个字符,然后重复步骤2。
  5. 重复步骤2到4,直到结束指针到达字符串的结尾。
  6. 记录窗口的最大长度。

实现代码

JavaScript

/**
 * 找到字符串中不含有重复字符的最长子串
 * @param {string} str 输入字符串
 * @return {number} 最长子串的长度
 */
const lengthOfLongestSubstring = (str) => {
  // 定义滑动窗口的开始和结束指针
  let start = 0;
  let end = 0;

  // 定义一个哈希表来存储字符及其最近出现的位置
  const charMap = {};

  // 定义无重复字符的最长子串的长度
  let maxLength = 0;

  // 遍历字符串
  while (end < str.length) {
    // 如果当前字符不在哈希表中,则将其添加到哈希表中并更新结束指针
    if (!charMap[str[end]]) {
      charMap[str[end]] = end;
      end++;
    } else {
      // 如果当前字符在哈希表中,则更新开始指针并更新哈希表
      start = Math.max(start, charMap[str[end]] + 1);
      charMap[str[end]] = end;
      end++;
    }

    // 更新无重复字符的最长子串的长度
    maxLength = Math.max(maxLength, end - start);
  }

  // 返回无重复字符的最长子串的长度
  return maxLength;
};

TypeScript

/**
 * 找到字符串中不含有重复字符的最长子串
 * @param {string} str 输入字符串
 * @return {number} 最长子串的长度
 */
const lengthOfLongestSubstring = (str: string): number => {
  // 定义滑动窗口的开始和结束指针
  let start = 0;
  let end = 0;

  // 定义一个哈希表来存储字符及其最近出现的位置
  const charMap: { [key: string]: number } = {};

  // 定义无重复字符的最长子串的长度
  let maxLength = 0;

  // 遍历字符串
  while (end < str.length) {
    // 如果当前字符不在哈希表中,则将其添加到哈希表中并更新结束指针
    if (!charMap[str[end]]) {
      charMap[str[end]] = end;
      end++;
    } else {
      // 如果当前字符在哈希表中,则更新开始指针并更新哈希表
      start = Math.max(start, charMap[str[end]] + 1);
      charMap[str[end]] = end;
      end++;
    }

    // 更新无重复字符的最长子串的长度
    maxLength = Math.max(maxLength, end - start);
  }

  // 返回无重复字符的最长子串的长度
  return maxLength;
};

Python

def length_of_longest_substring(str):
  """
  找到字符串中不含有重复字符的最长子串
  :param str: 输入字符串
  :return: 最长子串的长度
  """
  # 定义滑动窗口的开始和结束指针
  start = 0
  end = 0

  # 定义一个哈希表来存储字符及其最近出现的位置
  char_map = {}

  # 定义无重复字符的最长子串的长度
  max_length = 0

  # 遍历字符串
  while end < len(str):
    # 如果当前字符不在哈希表中,则将其添加到哈希表中并更新结束指针
    if str[end] not in char_map:
      char_map[str[end]] = end
      end += 1
    else:
      # 如果当前字符在哈希表中,则更新开始指针并更新哈希表
      start = max(start, char_map[str[end]] + 1)
      char_map[str[end]] = end
      end += 1

    # 更新无重复字符的最长子串的长度
    max_length = max(max_length, end - start)

  # 返回无重复字符的最长子串的长度
  return max_length

复杂度分析

滑动窗口算法的时间复杂度为 O(n),其中 n 是字符串的长度。这是因为算法只遍历字符串一次,并且在每次遍历中只执行常数次操作。

滑动窗口算法的空间复杂度为 O(min(n, k)),其中 k 是无重复字符的最长子串的长度。这是因为哈希表最多存储 k 个字符及其最近出现的位置。

扩展应用

滑动窗口算法可以用来解决许多其他问题,例如:

  • 寻找字符串中的最长回文子串
  • 寻找字符串中的最长重复子字符串
  • 寻找字符串中的最长公共子串
  • 寻找字符串中的最长子数组之和

滑动窗口算法是一个非常有用的算法,掌握它可以帮助我们解决许多实际问题。