3.8四数之和(LC18-M)

文章讲述了在解决四数之和问题时,如何使用双指针法以及进行有效的剪枝和去重优化。作者通过实例和代码演示了初始问题及修正后的代码,强调了正确处理边界条件和嵌套循环的重要性,以达到O(n^3)的时间复杂度和O(1)的空间复杂度。
摘要由CSDN通过智能技术生成

算法:

这道题和三数之和很像,都是用双指针法。

假设 nums[k]+nums[i]+nums[left]+nums[right]=target

只不过就是在i left right外面再加一层k的for循环。

但是要注意剪枝和去重。

还是先排序。

剪枝:比如对于k,当nums[k]>target and target>=0,这个时候肯定找不到符合条件的四元组了,return result

去重:比如对于k,当nums[k]==nums[k-1] continue

调试过程:

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        result=[]
        #双指针的前提:排序
        nums.sort()
        for k in range(len(nums)):
            i = k+1
            #对k剪枝
            if nums[k]>target and target>=0:
                return result
            #对k去重
            if k>=1 and nums[k] == nums[k-1]:
                continue
            for i in range(len(nums)):
                left = i+1
                right = len(nums)-1
                #对i剪枝,应该将nums[k]+nums[i]视作一体,因为i嵌套于k
                if nums[k]+nums[i]>target and target>=0:
                    return result
                #对i去重
                if i>=1 and nums[i] == nums[i-1]:
                    continue
                while left<right:
                    if nums[k] + nums[i] + nums[left] + nums[right] > target:
                        right -=1
                    if nums[k] + nums[i] + nums[left] + nums[right] < target:
                        left += 1
                    if nums[k] + nums[i] + nums[left] + nums[right] == target:
                        result.append([nums[k], nums[i], nums[left], nums[right]])
                    #对left和right去重
                    while left< right and nums[left] == nums[left+1]:
                        continue 
                    while left< right and nums[right] == nums[right-1]:
                        continue
                    left += 1
                    right -=1
        return result

            

原因:问题在这儿。i肯定在k后面,我这样的写法不对。for i in range(len(nums))还是从0开始遍历,应该改成 for i in range(k+1, len(nums))

相应地,去重部分也要改。

修改后:

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        result=[]
        #双指针的前提:排序
        nums.sort()
        for k in range(len(nums)):
            #对k剪枝
            if nums[k]>target and target>=0:
                return result
            #对k去重
            if k>=1 and nums[k] == nums[k-1]:
                continue
            for i in range(k+1, len(nums)):
                left = i+1
                right = len(nums)-1
                #对i剪枝,应该将nums[k]+nums[i]视作一体,因为i嵌套于k
                if nums[k]+nums[i]>target and target>=0:
                    return result
                #对i去重
                if i>=k+1 and nums[i] == nums[i-1]:
                    continue
                while left<right:
                    if nums[k] + nums[i] + nums[left] + nums[right] > target:
                        right -=1
                    if nums[k] + nums[i] + nums[left] + nums[right] < target:
                        left += 1
                    if nums[k] + nums[i] + nums[left] + nums[right] == target:
                        result.append([nums[k], nums[i], nums[left], nums[right]])
                    #对left和right去重
                    while left< right and nums[left] == nums[left+1]:
                        continue 
                    while left< right and nums[right] == nums[right-1]:
                        continue
                    left += 1
                    right -=1
        return result

            

检查后:

(1)比如[2,2,2,2,2],第一次遍历时,k=0,i=1,此时满足 i>=1 and nums[i] == nums[i-1] 就会continue,跳出循环。但是,这次遍历正确的输出应该是返回result.append([2,2,2,2]),

所以,应该改成:

if i>k+1 and nums[i] == nums[i-1]:

(2)去重不是用continue跳出循环,而是让left和right继续靠近。

所以,应该改成:

(3)去重操作是在满足nums[k] + nums[i] + nums[left] + nums[right] == target的前提下,才进行的,所以去重应该嵌套于该If语句

所以,应该改成:

还是不对,提交时发现:

(1)要把return result都改成break

  1. 使用 `break`
    当遇到 `break` 语句时,它会立即终止当前所在的循环(最内层循环),然后继续执行下一个语句,也就是外层循环的下一次迭代。换句话说,使用 `break` 会跳出内部循环,但仍然会继续执行外部循环的下一次迭代。最终,当外部循环结束时,函数会继续执行后面的语句,并返回结果列表 `result`

  2. 使用 `return result`
    当遇到 `return result` 语句时,它会立即终止当前函数的执行,并将结果列表 `result` 返回给调用者。换句话说,使用 `return result` 会立即结束函数的执行,并将结果返回给调用者,不再执行后面的语句。

因此,如果使用 `return result`,那么在找到第一个符合条件的四元组后,函数会立即终止执行,并将结果返回给调用者。这意味着函数不会继续执行后面的循环和语句,也不会进行后续的查找。这可能会导致返回的结果列表 `result` 不完整,只包含了找到的第一个符合条件的四元组。

而使用 `break`,则会继续执行后面的循环和语句,继续查找可能的四元组,直到外部循环结束,返回完整的结果列表 `result`

(2)要把

改成

三个并行的if会导致逻辑上的错误和不完整的结果。原因如下:

  1. 在正确的代码中,通过在循环内部使用 `if``elif` 和 `else` 来确保只执行一个条件满足的代码块。这样可以避免多次执行相同的操作。但是,如果将条件改变后,使用多个独立的 `if` 来判断,会导致多个条件同时满足时都执行相应的代码块。

  2. 在三个并行的if中,将条件 `nums[k] + nums[i] + nums[left] + nums[right] > target` 放在了第一个 `if` 语句中,但是没有相应的处理逻辑。这会导致当和大于目标时,循环会继续执行下去,而不是进行相应的处理。

因此,将循环条件和判断条件中的符号改变会导致逻辑错误和不正确的结果。

正确代码:

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        result=[]
        #双指针的前提:排序
        nums.sort()
        for k in range(len(nums)):
            #对k剪枝
            if nums[k]>target and target>=0 and nums[k]>0:
                break
            #对k去重
            if k>0 and nums[k] == nums[k-1]:
                continue
            for i in range(k+1, len(nums)):
                left = i+1
                right = len(nums)-1
                #对i剪枝,应该将nums[k]+nums[i]视作一体,因为i嵌套于k
                if nums[k]+nums[i]>target and target>=0:
                    break
                #对i去重
                if i>k+1 and nums[i] == nums[i-1]:
                    continue
                while left<right:                  
                    if nums[k] + nums[i] + nums[left] + nums[right] == target:
                        result.append([nums[k], nums[i], nums[left], nums[right]])
                        #对left和right去重
                        while left< right and nums[left] == nums[left+1]:
                            left += 1 
                        while left< right and nums[right] == nums[right-1]:
                            right -=1
                        left += 1
                        right -=1
                    elif nums[k] + nums[i] + nums[left] + nums[right] < target:
                        left += 1
                    else: 
                        right -=1

        return result

  • 8.12二刷:

  • # 给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
    # 0 <= a, b, c, d < n
    # a、b、c 和 d 互不相同
    # nums[a] + nums[b] + nums[c] + nums[d] == target
    # 你可以按 任意顺序 返回答案 。
    
    # 示例 1:
    # 输入:nums = [1,0,-1,0,-2,2], target = 0
    # 输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
    # 示例 2:
    # 输入:nums = [2,2,2,2,2], target = 8
    # 输出:[[2,2,2,2]]
    
    class Solution(object):
        def foursum(self, nums, target):
            nums.sort()#去重:排序
            #nums[a] + nums[b] + nums[c] + nums[d] == target
            #写代码的时候一定要牢记: nums[a] <= nums[b] <= nums[c] <= nums[d]
            res = list()
            for a in range(0, len(nums)):
                if a >=1 and nums[a] == nums[a-1]:
                    continue
                for b in range(a+1, len(nums)):
                    if b >= a+2 and nums[b] == nums[b-1]:
                        continue
                    x = nums[a] + nums[b]
                    c = b+1
                    d = len(nums)-1
                    while c < d:
                        if nums[c] + nums[d] == target - x:
                            res.append([nums[a], nums[b], nums[c], nums[d]])
                            c = c+1
                            d = d-1
                            #满足target时才需要去重
                            while c < d and nums[c] == nums[c-1]:
                                c = c+1
                                continue
                            while c < d and nums[d] == nums[d+1]:
                                d = d-1
                                continue                           
                        elif nums[c] + nums[d] > target - x:
                            d = d-1
                        elif nums[c] + nums[d] < target - x:
                            c = c+1
            return res
        
    nums = [1,0,-1,0,-2,2]
    target = 0
    res = Solution().foursum(nums, target)
    print(res)
                            
                            
    
                        
    

  • 时间复杂度: O(n^3)

  • 空间复杂度: O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值