Skip to content

Latest commit

 

History

History
88 lines (59 loc) · 3.43 KB

三数之和.md

File metadata and controls

88 lines (59 loc) · 3.43 KB

三数之和


题目描述

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

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

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

解释:

nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0

nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0

nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0

不同的三元组是 [-1,0,1][-1,-1,2]

注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]

输出:[]

解释:唯一可能的三元组和不为 0

示例 3:

输入:nums = [0,0,0]

输出:[[0,0,0]]

解释:唯一可能的三元组和为 0


解题思路

对于无序的输入数组,首先利用sort函数进行排序,然后利用双指针法,固定一个数,然后利用双指针在剩下的数中寻找和为0的两个数。 即将问题转换为在数组中遍历i,找到符合nums[j] + nums[k] = nums[i]jk,由此将问题转换为两数之和问题。

    for i in range(n - 2):
  • i的范围为0n-3,因为要保证i后面至少有两个数,即jk
    if self.nums[i] + self.nums[i + 1] + self.nums[i + 2] > 0:
        break
    if self.nums[i] + self.nums[n - 2] + self.nums[n - 1] < 0:
        continue
  • 在遍历i的过程中,分两种情况。如果i及其最近的两个数i+1i+2相加都>0,那说明后续不可能有相加等于0的情况,可以直接跳出循环。
  • 同理,如果i及其最后两个数n-2n-1相加都<0,那说明i及其前面的数相加都<0,可以跳过该i,继续遍历下一个i,因为随着nums[i]的增大,还可能存在相加=0的情况。
    if i > 0 and self.nums[i] == self.nums[i - 1]:
        continue
  • 由于题目说不可以包含重复的三元组,那么就需要每个遍历的i值与前面的值不相等。
  • 如果ii-1相等,则跳过该i,因为ii-1对应的结果已经计算过了,避免重复。
    else:
        ans.append([self.nums[i], self.nums[j], self.nums[k]])
        j += 1
        if j < k and self.nums[j] == self.nums[j - 1]:
            j += 1
        k -= 1
        if j < k and self.nums[k] == self.nums[k + 1]:
            k -= 1
  • 如果ijk相加等于0,则将结果添加到ans中,然后j指针右移,k指针左移,继续寻找下一个符合条件的jk
  • 但是在jk移动的过程中,如同i一样,也应注意避免重复。如果jj-1相等,则跳过该j,因为jj-1对应的结果已经计算过了,避免重复。同理,如果kk+1相等,则跳过该k,因为kk+1对应的结果已经计算过了,避免重复。

复杂度分析

  • 时间复杂度:O(n^2),其中 n 是数组 nums 的长度。排序问题最小的时间复杂度是 O(nlogn),枚举三元组的时间复杂度是 O(n^2),因此总时间复杂度是 O(n^2+nlogn)=O(n^2)
  • 空间复杂度:O(logn)或者O(1),其中 n 是数组 nums 的长度。空间复杂度主要取决于排序的空间复杂度,也可忽略排序的复杂度。