LeetCode 15. 3Sum(三数之和)

原题

Given an array nums of n integers, are there elements a, b, c in nums 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.

题目:

给定一个包含 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]
]

My solution

class Solution:
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        final_res = []
        nums = self.list_sort(nums)
        for i in range(len(nums)):
            for j in range(i+1, len(nums)):       
                for k in range(j+1, len(nums)):
                    if nums[i] + nums[j] + nums[k] == 0:
                        res.append([nums[i], nums[j], nums[k]])

        for i in range(len(res)):
            if res[i] not in final_res:
                final_res.append(res[i])
            else:
                pass

        return final_res

    def list_sort(self, nums):
        for i in range(len(nums)):
            for j in range(i, len(nums)):
                if nums[i] < nums[j]:
                    nums[j], nums[i] = nums[i], nums[j]
        return nums


Reference solution

分析:第一道题是两数之和,现在三数,后边会不会四数,五数?还真有四数哈哈。先看这一题,看题目示例看得出来,自动过滤掉了重复三元组,并且是排好序的格式输出,这里可以先将列表进行sort()方法排序。之后进行处理。

第一想法,是固定两个数,然后找第三个数是否在列表之中,且按照符合题意的形式输出。遍历所有情况可以用两层循环嵌套,之后判断第三个数是否在列表的切片之中。简单说步骤如下:

  1. 列表排序,sort()方法
  2. 两层循环嵌套,按照左到右(小到大的方向)遍历
  3. 判断第三个数(即第i,j,个数之和的相反数)是否在j之后的列表切片nums[j+1:]中

代码如下,应该很好理解!

class Solution:
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        #定义一个空列表,并将原列表排序
        result = []
        nums.sort()
        #原列表长度
        ly_len = len(nums)
        #遍历所有
        for i in range(ly_len-1):
            for j in range(i + 1,ly_len):
                #当前两数之和的相反数在列表切片nums[j+1:]中即可
                if -(nums[i]+nums[j]) in nums[j+1:]:
                    ly = [nums[i],nums[j],-(nums[i]+nums[j])]
                    if ly not in result:
                        result.append(ly)   
        return result

此方法,切实可行,只不过两层循环嵌套,在列表长度较大时会超时!

于是第二种想法。固定一个数,另外两个数之和为第一个数的相反数。这里主要是利用排序后的列表首位向中间逼近的思路执行。步骤介绍如下:

  1. 列表排序,sort()方法
  2. 一层循环,固定一个数,注意从第二个位置开始要考虑是不是和前一个位置的数值相等,避免做不必要的重复计算,比如代码中举例[-1,-1,0]
  3. 固定一个数后,另外两个数索引为除去第一个数的首尾位置。
  4. 取固定数的相反数为目标值target,如果另外两个数之和大于目标值,尾部索引减一,反之首部索引加一
  5. 不大不小即相等,记录这一个解,并首尾索引分别加减一,寻找其他解

代码如下所示:

class Solution:
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        #同上,空列表和排序
        res = []
        nums.sort()
        #固定一个数,另外两个数来匹配,凑0
        for i in range(0, len(nums)):
            #排序后可能存在相等的数连续,比如[-1,-1,0……];continue下次循环
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            target = 0 - nums[i] #另外两个数之和为target
            start, end = i + 1, len(nums) - 1#从后续列表切片两端向中间逼近
            while start < end:
                if nums[start] + nums[end] > target:
                    end -= 1  #如果首位之和大于目标值,尾部索引减一
                elif nums[start] + nums[end] < target:
                    start += 1#如果首位之和小于目标值,首部索引加一
                else:#等于目标值,则记录当前一组解,并寻找其他解
                    res.append((nums[i], nums[start], nums[end]))
                    end -= 1
                    start += 1
                    while start < end and nums[end] == nums[end + 1]:
                        end -= 1 #如果尾部连续两个数相等时,尾部索引减一
                    while start < end and nums[start] == nums[start - 1]:
                        start += 1#如果首部连续两个数相等时,首部索引加一
        return res                     

反思:

  1. 排序首先没有考虑到python自带的”.sort()”函数;
  2. 对于这种需要考虑多个数的情况,尽量避开多层循环,自己只考虑到了让第三个数满足要求,却没有考虑到固定一个数,读原列表进行排序,在从前后两边着手直接找到需要的两个数。

猜你喜欢

转载自blog.csdn.net/Dby_freedom/article/details/82598373
今日推荐