【leetcode刷题】20T10-三数之和

  • 2020 年 2 月 16 日
  • 筆記

木又同学2020年第10篇解题报告

leetcode第15题:三数之和

https://leetcode-cn.com/problems/3sum/


【题目】

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

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

示例:  给定数组 nums = [-1, 0, 1, 2, -1, -4],  满足要求的三元组集合为:  [    [-1, 0, 1],    [-1, -1, 2]  ]

【思路】

暴力解法,三层循环,判断三数相加是否为0;要想得到唯一的三元组,还需要再次判断。

当然可以优化,遇到时间复杂度太高的,一般可以先排个序。排序以后,即使是三层循环,第一个数大于0,由于后两个数均大于0,不可能三数之和等于0;同理,前两个数之和大于0,第三个数肯定大于0,三数之和也肯定不等于0。

再次优化,使用字典存储元素及该元素在数组中最后位置。这样,对于一组nums[p1]和nums[p2],查找nums[p2+1:]是否存在-nums[p1]-nums[p2]只需要O(1)的复杂度,时间复杂度降为O(n^2)

本来以为OK了,但是每次判断结果res中是否存在某个三元组,需要O(m)的时间,导致一直通不过所有case。其实,由于nums已经排序,得到的nums[p1],nums[p2]以及p2之后的-nums[p1]-nums[p3]肯定升序排列的。因此,只要保证nums[p1]和nums[p2]不同即可。

【代码】

python版本

class Solution(object):      def threeSum(self, nums):          """          :type nums: List[int]          :rtype: List[List[int]]          """          res = []          if len(nums) < 3:              return res            nums.sort()          # 存储下标,降低查找的时间复杂度          d = {}          for i, n in enumerate(nums):              d[n] = i            for i in range(len(nums)-2):              # 重复元素              if i > 0 and nums[i] == nums[i-1]:                  continue              # 最小的数大于0,其余的不用判断              if nums[i] > 0:                  break                for j in range(i+1, len(nums)-1):                  # nums[i] + nums[j] > 0,j后续元素都大于0,不用判断                  if nums[i] + nums[j] > 0:                      break                  if j > i+1 and nums[j] == nums[j-1]:                      continue                  if d.get(-nums[i]-nums[j], -1) > j:                      res.append([nums[i], nums[j], -nums[i]-nums[j]])          return res