返回

巧用指针,从有序数组中找出两数和,难题秒变易如反掌!

前端

最近,我碰到了一个有趣的问题:从一个已排序的数组中找出两个数,使得它们的和正好是输入的那个数字。而且,要将所有的组合列出来。

拿到这个问题,我第一时间想到的方法是用双重 for 循环遍历数组,穷举出所有的组合,再检查每个组合的和是否等于输入的数字。

def two_sum_brute_force(nums, target):
  """
  暴力法求解两数之和问题。

  :param nums: 有序数组
  :type nums: list
  :param target: 目标和
  :type target: int
  :return: 满足条件的两个数的组合,形式为[(num1, num2), ...]
  :rtype: list
  """

  result = []
  for i in range(len(nums)):
    for j in range(i + 1, len(nums)):
      if nums[i] + nums[j] == target:
        result.append((nums[i], nums[j]))

  return result

这个方法虽然简单,但时间复杂度是 O(n^2),对于大规模数组来说,效率非常低。

有没有更高效的方法来解决这个问题呢?

有的,那就是双指针法!

双指针法是一种用来解决有序数组中查找问题的经典算法。它的基本思想是:使用两个指针,一个指针指向数组的开头,另一个指针指向数组的结尾。然后,比较这两个指针指向的元素的和与目标和。如果和大于目标和,则将右指针向左移动;如果和小于目标和,则将左指针向右移动。重复这个过程,直到找到和等于目标和的两个元素。

def two_sum_two_pointers(nums, target):
  """
  双指针法求解两数之和问题。

  :param nums: 有序数组
  :type nums: list
  :param target: 目标和
  :type target: int
  :return: 满足条件的两个数的组合,形式为[(num1, num2), ...]
  :rtype: list
  """

  result = []
  left = 0
  right = len(nums) - 1

  while left < right:
    sum = nums[left] + nums[right]
    if sum == target:
      result.append((nums[left], nums[right]))

      # 跳过重复的元素
      left += 1
      while left < right and nums[left] == nums[left - 1]:
        left += 1

      # 跳过重复的元素
      right -= 1
      while left < right and nums[right] == nums[right + 1]:
        right -= 1
    elif sum < target:
      left += 1
    else:
      right -= 1

  return result

双指针法的速度要快得多,时间复杂度是 O(n)

除了双指针法,还有其他方法可以解决两数之和问题,比如哈希表法。但是,双指针法是最简单、最容易理解的方法之一。

掌握了双指针法,你就能轻松解决很多数组查找问题。