返回

双指针与滑动窗口:一个概念,两种实践

前端

破晓前的曙光

算法的世界就像一个浩瀚的宇宙,蕴藏着无数解题方法和优化策略。而在数组处理的领域中,有两颗璀璨的明星——滑动窗口和双指针算法。它们就像曙光,照亮了我们解决复杂问题的道路。

双指针:并肩齐驱,协作探索

双指针算法采用两个指针变量,它们携手并肩,沿着数组逐个元素地移动。当它们相遇时,便完成了对数组某个子区的处理。双指针算法的妙处在于,它可以在线性和时间复杂度内高效地处理各种问题,例如寻找子数组的最大和或最小值。

滑动窗口:动态收缩,局部聚焦

滑动窗口算法同样使用两个指针,但它们的工作方式却大相径庭。滑动窗口算法将一个固定大小的窗口置于数组上,然后通过移动窗口的左端或右端,逐个元素地滑动。在这个过程中,滑动窗口始终聚焦于数组中当前的局部区域,从而可以高效地解决一些特定问题,例如寻找特定模式的子串。

双指针与滑动窗口:殊途同归

尽管双指针和滑动窗口算法看似不同,但它们殊途同归,本质上都是通过两个指针变量来处理数组。双指针专注于数组的局部探索,而滑动窗口则侧重于局部收缩和聚焦。

实际应用:洞悉算法之美

为了进一步理解双指针和滑动窗口算法,让我们通过生动的实例来领略它们的魅力:

  • 双指针:寻找数组中的最长连续子数组

    def maxSubArray(nums: List[int]) -> int:
      left, right = 0, 0
      max_sum = nums[0]
      current_sum = nums[0]
    
      while right < len(nums):
        current_sum = max(nums[right], current_sum + nums[right])
        if current_sum > max_sum:
          max_sum = current_sum
          left, right = right, right + 1
        else:
          right += 1
    
      return max_sum
    
  • 滑动窗口:寻找数组中所有不重复的子字符串

    def findSubstring(s: str, words: List[str]) -> List[int]:
      word_count = collections.Counter(words)
      window_size = len(words) * len(words[0])
      start, end = 0, 0
      result = []
      current_word_count = collections.defaultdict(int)
    
      while end < len(s):
        current_word_count[s[end:end+len(words[0])]] += 1
    
        if current_word_count[s[end:end+len(words[0])] <= word_count[s[end:end+len(words[0])]]:
          if end - start + 1 == window_size:
            result.append(start)
            current_word_count[s[start:start+len(words[0])]] -= 1
            start += 1
        else:
          while current_word_count[s[end:end+len(words[0])]] > word_count[s[end:end+len(words[0])]]:
            current_word_count[s[start:start+len(words[0])]] -= 1
            start += 1
    
        end += 1
    
      return result
    

结语

双指针和滑动窗口算法是数组处理领域不可或缺的两把利器。它们以不同的方式使用两个指针变量,在不同类型的数组问题中大显身手。理解这两种算法的精髓,将极大地提升我们在解决复杂问题的效率和优雅度。