1-1

15.三数之和

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

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

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]

Python most votes solution:

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        nums.sort()
        for i in xrange(len(nums)-2):
            if i > 0 and nums[i] == nums[i-1]:
                continue
            l, r = i+1, len(nums)-1
            while l < r:
                s = nums[i] + nums[l] + nums[r]
                if s < 0:
                    l +=1 
                elif s > 0:
                    r -= 1
                else:
                    res.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 res

时间复杂度:\(O(n^2)\)

分析:

  • 首先排序,利用有序数组可以更快地找到想要的三元组;

  • xrange的用法

  • 第1个if判断从i=1开始生效,它的作用是跳过重复的元素。例如考虑如下序列:

    nums = [-1, 2, 2, 2, 2, 3, 3, 4, 4, 4, 4, 6]
    

    利用该if判断,程序会跳过前三个2,直接从第四个2开始运行if判断后面的程序,因为题目中要求答案中不可以包含重复的三元组,若不这样做则会产生重复的三元组;

  • lr可以看做是左右两个指针,如果s < 0,则左指针l右移,使其指向更大的数;同理,如果s > 0,则右指针r左移,使其指向更小的数;

  • 如果s = 0,则说明找到了想要的三元组,此时第一步操作是先将它们放进res中,因为有可能nums中满足题意的三元组并非只有这一组,因此要继续做判断:

    • 在左指针依旧在右指针左侧的前提下,

      (1)若左指针指向的当前位置的元素和它指向的下一个位置的元素(即左指针右移一位之后指向的元素)相等(此时就会出现题目中提到的“重复”的情况),因此要删除这种重复的情况。具体做法就是让左指针往右移一位就可以了。

      (2)同理,若右指针指向的当前位置的元素和它指向的下一个位置的元素(即右指针左移一位之后指向的元素)相等,就又会出现重复的情况,删除这种重复情况的方法是让右指针左移一位。

      (3)若终于左右指针均不再重复了(即下述nums序列中,左指针已经指向了从左往右数的最后一个2,右指针已经指向了从右往左数的最后一个4),则让左指针右移一位,同时右指针左移一位,继续在while循环中做判断。

      nums = [-1, 2, 2, 2, 2, 3, 3, 4, 4, 4, 4, 6]
      
  • 整个for循环总共要执行\(n-2\)次(i的值从nums中第一个元素nums[0]一直遍历到倒数第二个元素nums[n-3]

  • 在每一次进入while循环之前,左右指针的位置都会被重新定向,使左指针指向nums[i]右边紧邻的一个元素nums[i+1],右指针指向最后一个元素nums[n-1]。整个while循环会执行的次数为

    \[(n-1) - (i + 1) - 1 = n - i -3 \]

  • 因此,算法的整体时间复杂度为

    \[O(n-2) \times O(n - i -3) \approx O(n^2) \]

posted @ 2019-06-27 13:28  mingyu02  阅读(380)  评论(0编辑  收藏  举报