📜  门| GATE-CS-2004 |第 42 题(1)

📅  最后修改于: 2023-12-03 14:58:25.864000             🧑  作者: Mango

题目描述:

给定一个包含 $n$ 个整数的数组 $S$,和一个整数 $target$。

要求从 $S$ 中找到所有和为 $target$ 的不重复的三元组 $(a,b,c)$,并将它们按照元素从小到大的顺序输出。

注意,解决方案需要保证在输出结果中,不同的三元组不能重复。同一个三元组中的元素不能重复。

例如,对于数组 $S={-1,0,1,2,-1,-4}$,$target=0$,输出结果为 $[[-1, -1, 2], [-1, 0, 1]]$。

你需要实现以下函数:

def threeSum(nums: List[int], target: int) -> List[List[int]]:
    pass

输入

  • $nums$:一个包含 $n(3 ≤ n ≤ 10^3)$ 个整数的数组,每个整数都在 $-10^6$ 和 $10^6$ 之间。
  • $target$:一个整数,$target \in [-10^6,10^6]$。

输出

  • 返回所有和为 $target$ 的三元组,按元素从小到大的顺序输出,每个三元组单独作为一个列表返回,所有三元组组成一个列表。

示例

输入:nums = [-1,0,1,2,-1,-4], target = 0

输出:[[-1,-1,2],[-1,0,1]]

题解

这道题可以使用双指针进行解决,思路如下:

  1. 对数组进行排序,方便去重和确定双指针的移动方向。
  2. 遍历数组,以当前位置作为第一个数 $a$,然后在当前位置的右侧使用双指针 $l$ 和 $r$ 分别指向当前位置的下一个位置和数组末尾,并在每一步中计算 $a+l+r$ 的值 sum。
  3. 若 sum 小于 target,则左指针 $l$ 向右移动一位;若 sum 大于 target,则右指针 $r$ 向左移动一位;若 sum 等于 target,将当前三元组 $(a,l,r)$ 添加到结果集 ans 中,并判断左右指针所指的值是否与当前指针的值相等,相等则继续移动。
  4. 对于相同的值,只需计算一次即可,因此对于数组中重复的数进行去重,可用 set 去重。

具体的程序实现如下:

from typing import List

def threeSum(nums: List[int], target: int) -> List[List[int]]:
    ans = []
    n = len(nums)
    nums.sort()
    for i in range(n):
        if i > 0 and nums[i] == nums[i-1]:  # 去重
            continue
        l, r = i + 1, n - 1
        while l < r:
            s = nums[i] + nums[l] + nums[r]
            if s < target:
                l += 1
            elif s > target:
                r -= 1
            else:
                ans.append([nums[i], nums[l], nums[r]])
                while l < r and nums[l] == nums[l+1]:  # 去重
                    l += 1
                while l < r and nums[r] == nums[r-1]:  # 去重
                    r -= 1
                l += 1
                r -= 1
    return ans

测试一下我们的代码:

nums = [-1,0,1,2,-1,-4]
target = 0

print(threeSum(nums, target))

输出结果为:[[-1, -1, 2], [-1, 0, 1]],符合要求。