LeetCode-15. 3Sum(三数之和)

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

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

Example:

Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

方法一:有序数列首尾逼近查找

我们先来考虑两个数的情况。其它条件不变,假设查找两个元素a,b,使得a + b = 0。暴力方法是先确定一个数,然后在剩下的数中查找满足条件的数,这种算法是两重循环,时间复杂度为O(n²)。但如果我们的数组是有序的,即数组内数字从小到大排列,我们分别设置首尾两个指针 i,j。这样 i初始时指向组内最小数字, j初始时指向组内最大数字。通过比较 nums[i]+nums[j]和0的大小关系来对下标进行移动。如果比0小,那么需要将 i 向右移动,以增加总和。反之亦然。

那么对于三个数的情况,因为数组是一维的,只能设置首尾两个指针,因此需要先确定一个数,然后对剩下的两个数用上述逼近的方法进行查找。

同时要注意的是,题中所给数组中存在重复元素,而答案要求不包含重复的三元组。因此在进行查找时,应跳过重复数字。

这里对倒数第2行代码及其上方的两个while做一下说明:假设有一组数字[1,2,2,2,2,3,4,5,6,6,6,6,7],假设现在 j 指向最左端的2, k 指向最右端的6,那么经过两个while循环后,j 将指向最右端的2,k 将指向最左端的6,[1,2,2,2,2,3,4,5,6,6,6,6,7]。为了避免重复结果,j 和 k 仍然分别要继续移动一位,即倒数第二行代码。

#Python
class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums.sort()    #先对数组进行排序
        res = []
        for i in range(len(nums)-2):    #先确定第一个数,因为总共要有3个数,所以只能循环至倒数第三个数
            if i > 0 and nums[i] == nums[i-1]:    #如果后面的数和前面的相同,为避免重复答案,跳过这次循环
                continue
            j = i + 1;k = len(nums) - 1    #对剩下的两个数设置首尾指针
            while j < k:
                s = nums[i] + nums[j] + nums[k]
                if s < 0:
                    j = j + 1    #当前和比0小,需要增加当前的和,j右移
                elif s > 0:
                    k = k - 1    #当前和比0大,需要减小当前的和,k左移
                else:
                    res.append((nums[i],nums[j],nums[k]))    #找到满足条件的数
                    while j < k and nums[j] == nums[j+1]:    #左边移动到相同连续数字的最右端
                        j = j + 1
                    while j < k and nums[k] == nums[k-1]:    #右边移动到相同连续数字的最左端
                        k = k - 1
                    j = j + 1;k = k -1    #上面的操作结束后,两个指针所指的值只是位于相同值的末端,值本身没有变化本身,需要继续移动到不同数字上
        return res

猜你喜欢

转载自blog.csdn.net/theShepherd/article/details/86635686