15. 3Sum_左右开工,遍历找出符合目标的数字

时间:2023-03-09 03:36:25
15. 3Sum_左右开工,遍历找出符合目标的数字

题目:

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note: The solution set must not contain duplicate triplets.

For example, given array S = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
代码:
题目意思很简单:从数组中挑出三个数字,相加和为0,返回所有满足条件的结果:
第一反应,当然是遍历3次,吭哧吭哧写完了:
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums.sort()
        result = []
        for x in range(0,len(nums)-2):    
            for i in range(x+1,len(nums)-1):
                #print(i,nums[i],result)
                #if self.judge(nums[i],result):continue
                for j in range(i+1,len(nums)):
                    #if self.judge(nums[j],result):continue
                    if(nums[x]+nums[i]+nums[j]==0):
                        if [nums[x],nums[i],nums[j]] not in result:
                            result.append([nums[x],nums[i],nums[j]])                   
        return result
但是,问题来了,LeetCode提交测试会超时,测试数据是一串126个元素的数组,并且有120组符合条件的答案。
这种遍历的方法试了一下,大概需要0.36s,确实不快,必定时间复杂度有O(n^3)了
想啊想,试了很多种,都不行,只能百度了一下大神算法,一时,只用了0.003秒,而且准确的说,除去枚举第一个数之外,其余只需要遍历一遍:
总共的时间复杂度不到:O(n^2)
拷贝过来记录,并共大家参考学习:
    def threeSum2(self, nums):
        '''
            题意:求数列中三个数之和为0的三元组有多少个,需去重
            暴力枚举三个数复杂度为O(N^3)
            先考虑2Sum的做法,假设升序数列a,对于一组解ai,aj, 另一组解ak,al
            必然满足 i<k j>l 或 i>k j<l, 因此我们可以用两个指针,初始时指向数列两端
            指向数之和大于目标值时,右指针向左移使得总和减小,反之左指针向右移
            由此可以用O(N)的复杂度解决2Sum问题,3Sum则枚举第一个数O(N^2)
            使用有序数列的好处是,在枚举和移动指针时值相等的数可以跳过,省去去重部分
        '''       
        nums.sort()
        res = []
        length = len(nums)
        for i in range(0, length - 2):
            if i and nums[i] == nums[i - 1]:
                continue
            target = nums[i] * -1
            left, right = i + 1, length - 1
           
       while left < right:
                if nums[left] + nums[right] == target:
                    res.append([nums[i], nums[left], nums[right]])
                    right -= 1
                    left += 1
                    while left < right and nums[left] == nums[left - 1]:
                        left += 1
                    while left < right and nums[right] == nums[right + 1]:
                        right -= 1
                elif nums[left] + nums[right] > target:
                    right -= 1
                else:
                    left += 1
        return res