leetcode笔记-n数求和问题

两数之和

简单题,利用字典保存数和位置,查找target-n

def twoSum(self, nums, target):
        d = {}
        for i,num in enumerate(nums):
            if target-num in d:
                return d.get(target-num),i
            else:
                d[num] = i

三数之和

对数组进行排序,固定一个值,设置头尾两个指针,和小于移动头指针,和大于0移动尾指针。
一开始 将指针设置在固定值的两侧,由于探测了过多的重复情况导致超过时间限制。
后改为将指针,设在固定值之后,更改固定值时如果与之前相同就跳过。
当发现满足条件的组合时,也判断头尾指针与下一个值是否相同,相同则跳过,减少的操作次数

def threeSum(self,nums):
        nums.sort()
        ret = []
        for i,x in enumerate(nums):
            if x == nums[i-1] and i>0:
                continue
            j = i+1
            k = len(nums)-1
            while j<k:
                if nums[i]+nums[j]+nums[k] < 0:
                    j+=1
                elif nums[i]+nums[j]+nums[k] > 0:
                    k-=1
                else:
                    ans = [nums[i],nums[j],nums[k]]
                    ret.append(ans)
                    j+=1
                    k-=1
                    while j<k and nums[j] == nums[j-1]: 
                        j+=1
                    while j<k and nums[k] == nums[k+1]:
                        k-=1
        return ret

最接近的三数和

思路同上,注意接近时有可能大于目标值,或小于目标值。需要比较绝对值。

def threeSumClosest(self, nums, target):
        nums.sort()
        ans = 0
        min = 2 ** 31 - 1
        for i, x in enumerate(nums):
            if x == nums[i - 1] and i > 0:
                continue
            j = i + 1
            k = len(nums) - 1
            while j < k:
                if abs(target - (nums[i] + nums[j] + nums[k])) < min:
                    ans = nums[i] + nums[j] + nums[k]
                    min = abs(target - (nums[i] + nums[j] + nums[k]))
                if nums[i] + nums[j] + nums[k] < target:
                    j += 1
                    while j < k and nums[j] == nums[j - 1]:
                        j += 1
                elif nums[i] + nums[j] + nums[k] > target:
                    k -= 1
                    while j < k and nums[k] == nums[k + 1]:
                        k -= 1
                else:
                    return target
        return ans

四(n)数求和

遇到四数求和时,一开始以三数求和为基础,头尾分别固定一个值,利用对撞指针求解。
但是之后遇到5,6,7个数求和时,问题将变得更复杂。
考虑变为子集问题递归求解 找到长度为n 和为target的子集。
对于最后两组测试数据 会超过时间限制
考虑子集已排序,对于长度小于4时 如果填充当前项 已经超过 target 或者填充最大项仍小于target的部分 直接跳过;长度大于4 也跳过。优化后最后一组测试用例仍超时。
由于子集问题递归的过程相当于n重循环 对最后两重循环 也就是选择好2个数以后,用对撞指针减少一次循环。通过测试

    def fourSum(self, nums, target): 
        nums.sort()
        if len(nums)<4 or nums[-1]*4<target:
            return []
        def sub(nums,r,ret,target,n):
            if n<2:
                return
            if n == 2:
                i = 0
                j = len(nums)-1
                while i<j:
                    if nums[i] + nums[j] < target:
                        i+=1
                    elif nums[i] + nums[j] > target:
                        j-=1
                    else:
                        temp = r[:]
                        temp.append(nums[i])
                        temp.append(nums[j])
                        ret.append(temp)
                        while i<j and nums[i] == nums[i-1]:
                            i+=1
                        i+=1
                        while i<j and nums[j] == nums[j-1]:
                            j-=1
                        j-=1
                return
            else:
                for i,x in enumerate(nums[0:len(nums)-n+1]):
                    if i>0 and x==nums[i-1]:
                        continue
                    temp = r[:]
                    a = n * nums[-1]
                    b = n * x
                    if a < target or b > target:
                        break
                    temp.append(x)
                    sub(nums[i+1:],temp[:],ret,target-x,n-1)
        ret = []
        sub(nums,[],ret,target,4)
        return ret

此方法应适用于 n>2的求和问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值