返回

滑过有难度的算法面试题:滑过窗口

见解分享

滑动窗口算法简介

滑动窗口算法是一种在输入数据流上应用计算的通用技术。它通过在数据流上移动一个固定大小的窗口,并对窗口内的元素进行计算来工作。滑动窗口算法通常用于在线处理数据,例如实时分析、数据挖掘和机器学习。

滑动窗口算法的优点在于它能够在有限的内存空间内处理大量数据,并且具有较低的计算复杂度。这使得它非常适合处理实时数据或大规模数据集。

滑动窗口算法面试题

1. 最大子数组和

给定一个整数数组,找到连续子数组的最大和。

示例:

输入:[−2, 1, −3, 4, −1, 2, 1, −5, 4]
输出:6
解释:连续子数组 [4, -1, 2, 1] 的和最大,为 6。

解决方案:

def max_subarray_sum(nums):
  """
  找到连续子数组的最大和。

  参数:
    nums:一个整数数组。

  返回:
    连续子数组的最大和。
  """

  # 初始化最大和和当前和
  max_sum = float('-inf')
  current_sum = 0

  # 遍历数组
  for num in nums:
    # 更新当前和
    current_sum = max(num, current_sum + num)

    # 更新最大和
    max_sum = max(max_sum, current_sum)

  # 返回最大和
  return max_sum


# 测试
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print(max_subarray_sum(nums))  # 输出:6

2. 最长无重复子字符串

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

示例:

输入:"abcabcbb"
输出:3
解释:最长不包含重复字符的子字符串是 "abc"。

解决方案:

def longest_substring_without_repeating_characters(s):
  """
  找到最长不包含重复字符的子字符串的长度。

  参数:
    s:一个字符串。

  返回:
    最长不包含重复字符的子字符串的长度。
  """

  # 初始化最长子字符串长度和当前子字符串长度
  max_length = 0
  current_length = 0

  # 初始化一个字典来存储字符及其最后出现的位置
  char_index_map = {}

  # 遍历字符串
  for i, char in enumerate(s):
    # 如果字符在字典中,并且其最后出现的位置在当前子字符串中,则更新当前子字符串的长度
    if char in char_index_map and char_index_map[char] >= i - current_length:
      current_length = i - char_index_map[char]

    # 更新字符的最后出现位置
    char_index_map[char] = i

    # 更新最长子字符串长度
    max_length = max(max_length, current_length + 1)

  # 返回最长子字符串长度
  return max_length


# 测试
s = "abcabcbb"
print(longest_substring_without_repeating_characters(s))  # 输出:3

3. 最小覆盖子字符串

给定一个字符串和一个目标字符串,找到包含目标字符串的最小覆盖子字符串。

示例:

输入:"abcabcbb", "abc"
输出:"abc"
解释:包含目标字符串 "abc" 的最小覆盖子字符串是 "abc"。

解决方案:

def minimum_window_substring(s, t):
  """
  找到包含目标字符串的最小覆盖子字符串。

  参数:
    s:一个字符串。
    t:一个目标字符串。

  返回:
    包含目标字符串的最小覆盖子字符串。
  """

  # 初始化目标字符串中的字符及其频率
  char_freq = {}
  for char in t:
    if char not in char_freq:
      char_freq[char] = 0
    char_freq[char] += 1

  # 初始化滑动窗口的左右边界和最小覆盖子字符串的长度
  left = 0
  right = 0
  min_length = float('inf')
  min_substring = ""

  # 初始化满足条件的字符数
  satisfied_char_count = 0

  # 遍历字符串
  while right < len(s):
    # 如果当前字符在目标字符串中,并且其频率小于目标字符串中的频率,则更新满足条件的字符数
    if s[right] in char_freq and char_freq[s[right]] > 0:
      satisfied_char_count += 1

    # 更新目标字符串中的字符频率
    if s[right] in char_freq:
      char_freq[s[right]] -= 1

    # 如果满足条件的字符数等于目标字符串中的字符数,则更新最小覆盖子字符串的长度和子字符串
    while satisfied_char_count == len(char_freq):
      # 更新最小覆盖子字符串的长度和子字符串
      current_length = right - left + 1
      if current_length < min_length:
        min_length = current_length
        min_substring = s[left:right+1]

      # 更新目标字符串中的字符频率
      if s[left] in char_freq:
        char_freq[s[left]] += 1

      # 如果当前字符在目标字符串中,并且其频率大于 0,则更新满足条件的字符数
      if s[left] in char_freq and char_freq[s[left]] > 0:
        satisfied_char_count -= 1

      # 移动左边界
      left += 1

    # 移动右边界
    right += 1

  # 返回最小覆盖子字符串
  return min_substring


# 测试
s = "abcabcbb"
t = "abc"
print(minimum_window_substring(s, t))  # 输出:"abc"