• LeetCode 15.[👁] 3Sum


    三数之和

    先锁定前两个,第三个游标查后面的,之后再前进第二个游标。到末尾再前进第一个游标。

    first submission
    class Solution:
        def threeSum(self, nums):
            """
            :type nums: List[int]
            :rtype: List[List[int]]
            """
            rList=[]
            ai=0
            bi=ai+1
            ci=ai+2
    
            ll=len(nums)-1
    
            while ci<ll: 
                c=0-nums[ai]-nums[bi]
                while ci<ll:
                    if nums[ci]==c:
                        oneList=sorted([nums[ai],nums[bi],nums[ci]])
                        if oneList not in rList:
                            rList.append(oneList)
                    ci+=1
                bi+=1
                ci=bi+1
    
            return rList
    

    Wrong Answer:

    Input:
        [0,0,0]
    Output:
        []
    Expected:
        [[0,0,0]]
    

    边界忘了算上

    Input:
        [3,0,-2,-1,1,2]
    Output:
        [[-2,-1,3]]
    Expected:
        [[-2,-1,3],[-2,0,2],[-1,0,1]]
    

    没移动a游标

    second submission
    class Solution:
        def threeSum(self, nums):
            """
            :type nums: List[int]
            :rtype: List[List[int]]
            """
            rList=[]
            ai=0
            bi=ai+1
            ci=ai+2
    
            ll=len(nums)
    
            while ci<ll: 
                c=0-nums[ai]-nums[bi]
                while ci<ll:
                    if nums[ci]==c:
                        oneList=sorted([nums[ai],nums[bi],nums[ci]])
                        if oneList not in rList:
                            rList.append(oneList)
                    ci+=1
    
                bi+=1
                ci=bi+1
    
                if ci==ll:
                    # end is move a  
                    ai+=1
                    bi=ai+1
                    ci=ai+2
                    
    
            return rList
    

    Time Limit Exceeded:命名为测试点2

    Last executed input:
    [3,13,8,-8,-15,-3,13,-3,-12,-7,2,-3,-8,10,0,-12,5,13,13,8,6,-11,6,-10,-13,14,-9,9,5,7,12,-14,5,-3,-7,-3,10,13,9,5,13,-4,-12,-9,13,-5,-14,3,-7,6,-12,7,10,10,12,12,9,10,-2,-9,2,-5,-8,14,0,-8,-4,-13,12,12,7,11,-15,2,-13,5,12,10,-14,13,1,-11,-3,-12,14,-6,-15,8,11,-10,7,-10,-7,14,11,8,14,14,10,11,11,-6]
    

    想到笨拙的解法会超时,这么点数据就超时了。现在我的电脑25ms

    用了index()在右侧查找第三个数c,本地时间缩短到8ms:

    third submission
    class Solution:
        def threeSum(self, nums):
            """
            :type nums: List[int]
            :rtype: List[List[int]]
            """
            nums=sorted(nums);
    
            rList=[]
            ai=0
            bi=ai+1
            ci=ai+2
    
            ll=len(nums)
    
            while bi<ll-1: 
                c=0-nums[ai]-nums[bi]
                
                try:
                    # find c
                    nums[bi+1:].index(c)
                    #print('ok')
                    oneList=sorted([nums[ai],nums[bi],c])
                    if oneList not in rList:
                        rList.append(oneList)
                except:
                    #print('error')
                    pass
    
                bi+=1
    
                if bi==ll-1:
                    # end is move a  
                    ai+=1
                    bi=ai+1
                    
            return rList
    

    Time Limit Exceeded:
    命名为测试点3

    Last executed input:
    [82597,-9243,62390,83030,...,-97960,-23904,78409,-7418,77916]
    

    1分钟!!摔。有很多数据可以跳过,比如俩负数,下一个肯定得找正的,做了无用功。但我还没想到一个合适的办法。

    测试点2,缩小到了 3ms

    class Solution:
        def threeSum(self, nums):
            """
            :type nums: List[int]
            :rtype: List[List[int]]
            """
            nums=sorted(nums);
            #print(nums)
            rList=[]
            ai=0
    
            ll=len(nums)
    
            nextc=ll
            prevB=0
    
            while ai<ll:
                bi=ai+1
                if nums[ai]>0:
                    break
                while bi<nextc:
                    c=0-nums[ai]-nums[bi]
                    
                    # 负数已完
                    if c<0 or nums[ai]>0:
                        break
    
                    if c in nums[bi+1:nextc]:
                        # find c
                        oneList=sorted([nums[ai],nums[bi],c])
                        if oneList not in rList:
                            rList.append(oneList)
                            nextc=nums.index(c)
    
                        #print(nums[bi+1:nextc],nextc)
                    bi+=1
                ai+=1
                nextc=ll
                    
            return rList
    

    还是太臃肿了,而且最后一个超时节点也过不去。甚至本地都没出来啊。换个类似双指针的思路。

    class Solution:
        def threeSum(self, nums):
            """
            :type nums: List[int]
            :rtype: List[List[int]]
            """
            nums=sorted(nums);
            #print(nums)
            rList=[]
            
            ll=len(nums)
            start=0
            middle=start+1
            end=ll-1
    
            while middle<end:
                if nums[start]>0:
                    break
    
                #print(start,middle,end,[nums[start],nums[middle],nums[end]],0-nums[end]-nums[start]==nums[middle])
                if nums[end]+nums[start]<-nums[middle]:
                    middle+=1
                    
                elif nums[start]+nums[middle]>-nums[end]:
                    end-=1
    
                else:
                    oneList=sorted([nums[start],nums[middle],nums[end]])
                    if oneList not in rList:
                        rList.append(oneList)
                    middle+=1
                    end-=1
    
                if middle>=end:
                    start+=1
                    middle=start+1
                    end=ll-1
            return rList
    

    测试点2 2.5ms (对比之前3ms应该算是差不多没有改进),测试点3终于出来了: 4.7s,还是很长,不敢去测,再想着笨拙的优化一下?提交一下吧,弄不出来了。

    依旧超时

    看讨论区一个O(N*N)的python解法:

    by https://leetcode.com/problems/3sum/discuss/7392/Python-easy-to-understand-solution-(O(n*n)-time).
    
    def threeSum(self, nums):
        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
    

    和我的想法差不多,代码都好像啊,试着分析一下为啥我的通不过。只改我认为不同的地方:现在时间4.7-4.8s

    • sorted()和list.sort()。
      • 暂时不分析排序的不同性能,替换一下也几乎没影响。
    • 首先跳过了相等的数字
      • 我也添加一个,时间5.2s竟然增加了0.4s耗时
    • 将三个值算出来和0做对比
      • 这里是应该优化,虽然感觉不重要 spend time: 4.3710356s 少了0.4s
    • while排除重复的l r 对于我没有作用,不用管
    • 添加方式不管才是我为啥费时的原因,他用的元祖不用判断重复,并且append快速。我换了元组之后时间是spend time: 1.836852s. 原来可以用元组的,最后测试发现网站自己会转为列表
    maybe seventh submission
    class Solution:
        def threeSum(self, nums):
            """
            :type nums: List[int]
            :rtype: List[List[int]]
            """
            nums=sorted(nums)
            rList=[]
            
            ll=len(nums)
            start=0
            middle=start+1
            end=ll-1
    
            while middle<end:
                if nums[start]>0:
                    break
                #+ spend time + 0.4s
                if start>0 and nums[start] == nums[start-1]:
                    start+=1
                    continue
    
                #print(start,middle,end,[nums[start],nums[middle],nums[end]],0-nums[end]-nums[start]==nums[middle])
                s=nums[start]+nums[middle]+nums[end]
                if s<0:
                    middle+=1
                    
                elif s>0:
                    end-=1
    
                else:
                    rList.append((nums[start],nums[middle],nums[end]))
                    middle+=1
                    end-=1
    
                if middle>=end:
                    start+=1
                    middle=start+1
                    end=ll-1
            return rList
    

    Runtime Error

    Runtime Error Message:
    Line 16: IndexError: list index out of range
    Last executed input:
    [0,0,0,0]
    

    再改一下,spend time: 0.3842164

    Wrong Answer

     
    Input:
    [-2,0,0,2,2]
    Output:
    [[-2,0,2],[-2,0,2]]
    Expected:
    [[-2,0,2]]
    

    好吧,外层改成for用start遍历,现在的状态和那个解法就差不离了,提交那个讨论区1s+的吧 ><

    后续:
    讨论区还发现一个声称胜过94%的答案,本地0.5s可以参考。用字典存起来每个数字的个数,以便跳过,那两个考虑left right的if我是想不出来的。

    by https://leetcode.com/problems/3sum/discuss/155425/beates-94-python3-solution
        if len(nums)<3:
            return []
        if len(nums) == 3 and nums[0] + nums[1] + nums[2] == 0:
            return [nums]
        nums.sort()
        list = []
        map = {}
        le = len(nums)
        for i in nums:
            if i in map:
                map[i] += 1
            else:
                map[i] = 1
        i = 0
        while i < le and nums[i] <= 0:
            j = i + 1
            left = nums[i]
            while j < le:
                right = nums[j]
                need = 0 - left - right
                if need < right:
                    break
                if need not in map:
                    if left == right:
                        j += (map[right] - 1)
                    else:
                        j += map[right]
                    continue
                if left == right and (need > right or (need == right and map[need] > 2)):
                    list.append([left, left, need])
                    j += (map[right] - 1)
                elif left != right and ((need == right and map[need] > 1) or need > right):
                    list.append([left, right, need])
                    j += map[right]
                else:
                    j += map[right]
            i += map[left]
        return list
    
  • 相关阅读:
    broncho a1 hack指南-准备硬件
    嵌入式GUI ftk0.1发布
    ASP.net页面防刷新
    C#反射入门教程(转)
    万物生萨顶顶
    [转载内容]C# win程序中主窗体菜单的权限控制
    VB.net技巧更新(一)
    XML与dataset里相互读取操作
    操作EXCEL代码(c#完全版)
    [转载内容]动态创建菜单,menustrip,根据权限显示菜单,控制菜单可用,反射,给窗体传值,反射对象传值,public static Object CreateInstance ( Type type, params Object[] args )
  • 原文地址:https://www.cnblogs.com/warcraft/p/9401019.html
Copyright © 2020-2023  润新知