力扣第18题. 四数之和

题目:

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:

答案中不可以包含重复的四元组。

示例: 给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。 满足要求的四元组集合为: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]

Python3解答代码:

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        # 排序nums数组
        nums.sort()
        # 初始化变量,初始化一个空列表result用于存储结果
        n = len(nums)
        result = []

        # 循环每个可能作为四元组的第一个数字nums[i]
        for i in range(n):
            # 如果 nums[i] 大于 target 并且都为正数,后续元素只会更大,就可以提前结束当前循环,
            # 因为不可能存在四个数的和等于 target
            if nums[i] > target and nums[i] > 0 and target > 0:
                break
            # 第一层循环中的元素 nums[i],如果当前元素与前一个元素相同,则直接跳过,避免重复计算
            if i > 0 and nums[i] == nums[i-1]:
                continue
            # 内层循环遍历每个可能作为四元组第二个数字的 nums[j]
            for j in range(i+1, n):
                if nums[i] + nums[j] > target and target > 0:
                    break
                # 跳过相同的 nums[j] 值以避免重复的四元组。
                if j > i+1 and nums[j] == nums[j-1]:
                    continue
                
                # 确定两个数之后,使用双指针来查找后两个数,使得四数之和等于target、
                left,right = j+1, n-1
                while left < right:
                    # 计算选中的四个数之和s
                    s = nums[i] + nums[j] + nums[left] + nums[right]
                    if s == target:
                        result.append([nums[i], nums[j], nums[left], nums[right]])
                        # 为了避免重复的四元组,需要移动left和right来跳过重复的元素
                        # 只要 left 指向的元素与其右边相邻的元素相同,就继续向右移动 left 指针
                        while left < right and nums[left] == nums[left+1]:
                            left += 1
                        # 只要 right 指向的元素与其左边相邻的元素相同,就继续向左移动 right 指针
                        while left < right and nums[right] == nums[right-1]:
                            right -= 1
                        # 完成上述循环后,需要将 left 和 right 分别再向中间移动一位,
                        # 以避免重复计算当前的组合
                        left += 1
                        right -= 1
                    #  四数之和小于目标值,需要将left指针向右移动
                    elif s < target:
                        left += 1
                    # 四数之和大于目标值,为了减少和的大小
                    # 需要将 right 指针向左移动,即向更小的数移动
                    else:
                         right -= 1

        return result

上述代码实现过程解析:

上述代码实现了在给定整数数组 nums 中找出所有四个元素的组合,使得它们的和等于目标值 target。下面是代码的详细解释:

  1. 排序数组:首先,对输入的整数数组 nums 进行排序。这样做的目的是为了在后续的处理中能更方便地进行去重和剪枝操作。

  2. 初始化变量:获取数组的长度 n,并初始化一个空列表 result 用于存储结果。

  3. 遍历数组:使用两层循环遍历数组,首先固定两个数 nums[i]nums[j],其中 ij 分别表示第一层循环和第二层循环的索引。这两个数将作为四个元素中的前两个。

  4. 剪枝操作:在第一层循环中,有两处剪枝操作:

    • 如果当前的 nums[i] 大于 target 并且都为正数,就可以提前结束当前循环,因为后续元素只会更大,不可能满足条件。
    • 在第二层循环中,如果当前的 nums[i] + nums[j] 大于 target 并且 target 为正数,同样可以提前结束当前循环。
  5. 去重操作:**在每一层循环中,都需要进行去重操作,以避免重复的组合被计算。具体做法是:

    • 对于第一层循环中的元素 nums[i],如果当前元素与前一个元素相同,则直接跳过,避免重复计算。
    • 对于第二层循环中的元素 nums[j],如果当前元素与前一个元素相同,则直接跳过,避免重复计算。
  6. 双指针法找到剩余两个数:**在固定了前两个数后,剩余的两个数采用双指针法。定义两个指针 leftright 分别指向当前范围内的最左和最右的元素。然后循环移动这两个指针,不断调整它们指向的元素,直到找到符合条件的组合或者两个指针相遇。

  7. 判断条件和更新指针:

    • 如果四个数的和等于目标值 target,则将这个组合添加到结果列表 result 中,并同时更新指针 leftright,以避免重复计算相同的组合。
    • 如果四个数的和小于目标值 target,则将左指针 left 右移一位。
    • 如果四个数的和大于目标值 target,则将右指针 right 左移一位。
  8. 返回结果:最终返回结果列表 result,其中存储了所有满足条件的四个元素的组合。

重难点解释:

1.剪枝操作:

"剪枝"指的是在搜索过程中通过一些条件判断提前结束不必要的搜索分支,从而减少搜索空间,提高算法效率。具体来说,这段代码中的剪枝操作有两个地方:

  1. 在第一层循环和第二层循环中,通过比较当前元素与目标值的大小关系,如果可以确定后续元素无法满足条件,就提前结束当前循环。例如,在第一层循环中,如果 nums[i] 大于 target 并且都为正数,后续元素只会更大,就可以提前结束当前循环,因为不可能存在四个数的和等于 target

  2. 在第二层循环中,通过比较当前两个元素的和与目标值的大小关系,同样可以提前结束当前循环。如果 nums[i] + nums[j] 大于 target 并且 target 为正数,后续元素只会更大,也可以提前结束当前循环。

2.if j > i+1 and nums[j] == nums[j-1]: continue 解释为啥是i+1

这段代码的意图是在固定了第一个数字 nums[i] 后,跳过那些可能会导致重复四元组的第二个数字 nums[j]。这里的逻辑是:

  • j > i+1:这个条件用于确保 j 不仅仅是在 i+1 的位置上,也就是说,j 应该至少是从 i+2 的位置开始考虑。这是因为:

    • j == i+1 时,nums[j] 是在 nums[i] 后面的第一个元素,此时没有前一个元素 nums[j-1] 与之相比较,因此不需要进行去重判断。
    • j > i+1 时,表示 j 至少是第三个考虑的元素,此时 nums[j-1] 存在,并且位于 nums[j] 之前,因此可以进行重复检查。
  • nums[j] == nums[j-1]:这个条件检查当前的元素 nums[j] 是否与它前一个元素 nums[j-1] 相等。如果相等,说明使用当前的 nums[j] 可能会生成与前一个循环相同的四元组,因此应该跳过当前的 nums[j]

目的和重要性

  • 防止重复结果:如果不进行这样的去重,相同的 nums[j] 值将在内层循环中多次使用,与同一个 nums[i] 结合,可能会导致生成重复的四元组。
  • 提高效率:通过跳过重复元素,可以减少不必要的计算和迭代,这对于处理大数据集时尤为重要。

3.核心代码解释:

if nums[i] + nums[j] > target and target > 0:
    break

限制 target > 0 的原因主要是为了确保当目标值 target 是正数时,这个剪枝逻辑才会生效。这样的条件设定对于整体算法的正确性和效率都有影响,以下是几个关键点:

1. 保证剪枝的适用性

target 是正数时,如果两个数的和已经超过了 target,继续在正数范围内添加更多的数会使得总和进一步增加,从而不可能等于 target。这个逻辑在 target 是正数时显然有效。

2. 处理负数情况

如果 target 是负数或零,上述剪枝条件可能不适用,因为:

  • target 是零或负数时,可能需要包括负数在内的组合来达到 target。即使当前的两数之和已经超过了 target,通过选择负数作为其他组成部分,仍然有可能将总和调整至 target
  • 对于负 target,若当前两数之和大于 target,但它们之间存在足够大的负数,这些负数仍然可以使得最终的四数之和等于 target

3. 避免不必要的逻辑应用

如果不加 target > 0 这个条件,那么对于负数 targettarget 为零的情况,剪枝可能导致漏掉有效的解。例如,假设 target = -10,如果仅仅因为两个正数的和大于 -10 就停止搜索,可能会错过一些包含负数且其和为 -10 的有效组合。

解释一下这个几句代码的实现:

 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 s < target:
                        left += 1
                    else:
                        right -= 1
        return result

代码位于双指针搜索的环节,用于在已经固定了两个数字之后,在数组的剩余部分中寻找两个数,使得这四个数的和等于给定的目标 target。这一部分是通过移动左指针 left 和右指针 right 来实现的。下面是详细的逻辑解释:

判断当前四数之和 s

s = nums[i] + nums[j] + nums[left] + nums[right]

首先计算当前选定的四个数的和 s,并将其与目标 target 进行比较。

判断三种情况

  • 四数之和等于目标值 (s == target)

    • 将符合条件的四元组 [nums[i], nums[j], nums[left], nums[right]] 添加到结果列表 result 中。

    • 接下来,为了避免重复的四元组,需要移动 leftright 指针来跳过所有相同的元素。

    • 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
      

      • 这两个 while 循环分别用于:

      • 完成上述循环后,需要将 leftright 分别再向中间移动一位,以避免重复计算当前的组合。
      • 跳过右边重复的元素:只要 right 指向的元素与其左边相邻的元素相同,就继续向左移动 right 指针。
      • 跳过左边重复的元素:只要 left 指向的元素与其右边相邻的元素相同,就继续向右移动 left 指针。
  • 四数之和小于目标值 (s < target)

    • 为了增加和的大小,需要将 left 指针向右移动,即向更大的数移动。

      • left += 1

  • 四数之和大于目标值 (s > target)

    • 为了减少和的大小,需要将 right 指针向左移动,即向更小的数移动。

right -= 1

 综上,本文的对于力扣18. 四数之和的Python3解答,仅仅是个人学习资料记录,也十分高兴我的见解可以帮助其他的正在做这个题目的同学,基础较差,仅仅是个人见解,大神勿喷,欢迎交流,谢谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/549685.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用VLC无法播放安防监控EasyCVR平台分发出的FLV视频流,是什么原因?

安防视频汇聚平台EasyCVR不仅可支持的接入协议非常多&#xff08;包括&#xff1a;国标GB28181、RTSP/Onvif、RTMP&#xff0c;以及厂家的私有协议与SDK&#xff0c;如&#xff1a;海康ehome、海康sdk、大华sdk、宇视sdk、华为sdk、萤石云sdk、乐橙sdk等&#xff09;&#xff0…

数据结构线性表篇-顺序表的实现

1.数据结构的介绍 ⚀基本概念 数据结构 数据 结构 数据&#xff1a; 数据就是所有描述客观事物的符号。比如&#xff1a;我们常见的文字&#xff0c;“你今天学习了吗&#xff1f;”&#xff1b;数字&#xff0c;“1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&a…

基于RflySim平台的uORB消息读取与写入实验(一)

uORB消息读取与写入实验框架总览 一. 总体说明 —文件目录 uORB消息读取与写入例程目录&#xff1a; [安装目录]\RflySimAPIs\5.RflySimFlyCtrl\0.ApiExps\6.uORB-Read-Write 自定义uORB消息例程目录&#xff1a; [安装目录]\5.RflySimFlyCtrl\0.ApiExps\7.uORB-Create 二…

Linux三剑客之awk篇

目录 1、awk 1.1、awk参数 1.2、awk变量 1.3、awk分割符 1.3.1、FS 1.3.2、OFS 1.3.3、RS 1.3.4、ORS 1.3.5、NF 1.3.6、NR 1.3.7、FNR 1.3.8、FILENAME 1.3.9、ARGC与ARGV 1.4、自定义变量 1.5、printf格式化输出 1、awk 作用&#xff1a;具有强大的文本格式化…

【多线程】阻塞队列 | put()方法 | take()方法 | 生产者-消费者模式 |实现阻塞队列

文章目录 阻塞队列1.生产者-消费者模式生产者消费者模型的意义&#xff1a;1.解耦合2.削峰填谷&#xff1a; 2.阻塞队列的使用BlockingQueue 3.实现阻塞队列唤醒&#xff1a;使用阻塞队列实现生产者消费者模型 阻塞队列 阻塞队列是一种特殊的队列&#xff1a; 1.是线程安全的。…

视频自定义字幕,中英文,彩色的,你也可以,不会不知道吧

前言 关于【SSD系列】&#xff1a; 前端一些有意思的内容&#xff0c;旨在3-10分钟里&#xff0c;有所获&#xff0c;又不为所累。 字幕&#xff0c;大家见过吧&#xff0c;其实你也可以&#xff0c;真的可以&#xff0c;真的真的可以。不难&#xff0c;不难&#xff0c;真的…

leetcode1448.统计二叉树中的好节点数目

1. 题目描述 题目链接 2. 解题思路 首先看一下题目的“核心”&#xff0c;什么是好节点&#xff1a;从根到该节点 X 所经过的节点中&#xff0c;没有任何节点的值大于 X 的值。也就是说&#xff0c;我们只要知道了从根节点到该节点的所有的值&#xff0c;就可以判断该节点是…

优斯特:防静电包装解决方案的巧妙运用

在现代电子产品生产与运输领域&#xff0c;防静电包装已成为保障产品安全的必备环节。优斯特凭借其创新的防静电包装解决方案&#xff0c;为客户提供了一种巧妙的方式来确保产品在存储和运输过程中不受静电影响&#xff0c;并且不会被刮花或损坏。 静电对产品的影响 静电对电子…

数学建模--深入剖析线性规划(模型全方位解读+代码分析)

1.简介 &#xff08;1&#xff09;线性规划三要素 &#xff08;2&#xff09;模型适用赛题 2.典例讲解 &#xff08;1&#xff09;问题分析 目标函数是净收益尽可能大&#xff0c;风险尽可能小&#xff1b; 约束条件是交易费的分段函数&#xff0c;以及每一笔投资都是非负数&am…

java绘图在ubuntu报错

把JRT网站部署到ubuntu桌面系统上&#xff0c;开始没测试绘图部分功能&#xff0c;只试了连PostGreSql部分正常。后面试了生成位图部分发现报错。 报下面错误&#xff1a; (ColorModel.java:220)\n\tat java.desktop/java.awt.image.BufferedImage.(BufferedImage.java:286)\n…

阿赵UE学习笔记——28、粒子系统Niagara简介

阿赵UE学习笔记目录 大家好&#xff0c;我是阿赵。   继续学习虚幻引擎的使用。这次开始学习粒子系统的使用。 一、Cascade系统 在介绍UE5的Niagara系统之前&#xff0c;必须先介绍一下旧版本的粒子系统。   在UE4的时候&#xff0c;虚幻引擎的粒子系统叫做Cascade&#x…

【iOS】——SDWebImage源码学习

文章目录 一、SDWebIamge简介二、SDWebImage的调用流程SDWebImage源码分析1.UIImageViewWebCache层2.UIViewWebCache层3.SDWebManager层4.SDWebCache层5.SDWebImageDownloader层 一、SDWebIamge简介 SDWebImage是iOS中提供图片加载的第三方库&#xff0c;可以给UIKit框架中的控…

思维导图ai生成软件分享5款好用的!

思维导图ai生成软件分享5款好用的&#xff01; 在快节奏的信息时代&#xff0c;思维导图作为一种有效的思维整理工具&#xff0c;越来越受到人们的青睐。它能够将复杂的思维过程可视化&#xff0c;帮助我们更好地梳理思路、规划工作。近年来&#xff0c;随着人工智能技术的飞速…

整数运算超越存储单元表示范围:上溢出、下溢出、回绕

示例&#xff1a; /*** brief how about integer-underflow-overflow? show you here.* author wenxuanpei* email 15873152445163.com(query for any question here)*/ #define _CRT_SECURE_NO_WARNINGS//support c-library in Microsoft-Visual-Studio #include <std…

408数据结构,怎么练习算法大题?

其实考研的数据结构算法题是有得分技巧的 得分要点 会写结构定义&#xff08;没有就自己写上&#xff09;写清楚解题的算法思想描述清楚算法实现最后写出时间和空间复杂度 以上这四步是完成一道算法题的基本步骤&#xff0c;也是其中得分的主要地方就是后面两步。但是前面两…

java-spring 图灵 04

在Spring框架中&#xff0c;可以使用org.springframework.core.io.support.ResourcePatternResolver接口的resolveBasePackage方法来将指定的基础包解析为用于包搜索路径的模式规范。 例如&#xff0c;如果基础包是com.example.app&#xff0c;则可以使用resolveBasePackage方法…

【深度学习】【机器学习】用神经网络进行入侵检测,NSL-KDD数据集,基于机器学习(深度学习)判断网络入侵,网络攻击,流量异常【3】

之前用NSL-KDD数据集做入侵检测的项目是&#xff1a; 【1】https://qq742971636.blog.csdn.net/article/details/137082925 【2】https://qq742971636.blog.csdn.net/article/details/137170933 有人问我是不是可以改代码&#xff0c;我说可以。 训练 我将NSL_KDD_Final_1.i…

Open3D 无效点滤波(32)

Open3D 无效点滤波(32) 一、算法介绍二、算法实现1.代码2.效果一、算法介绍 这个算法的目标是从点云数据中去除无效的点,这些无效点可能是由于坐标值为无穷大(inf)或者不是数字(NaN)而产生的。这些无效点可能会导致后续处理步骤出现错误或异常,因此在处理点云数据时需…

品深茶创始人是谁?

据说&#xff0c;品深茶的创始人之前是一个程序员&#xff0c;他在软件行业工作十多年&#xff0c;由于常年熬夜加班再加上抽烟喝酒等不良习惯&#xff0c;导致在一次体检中被查出患上了肾癌&#xff0c;对他来说&#xff0c;期待的财务自由还没实现&#xff0c;身体就已经完蛋…

java(网络编程)

什么是网络编程? 在网络通信协议下&#xff0c;不同计算机上运行的程序&#xff0c;进行的数据传输。 应用场景&#xff1a;即时通信、网游对战、金融证券、国际贸易、邮件、等等 不管是什么场景&#xff0c;都是计算机跟计算机之间通过网络进行数据传输 Java中可以使用ja…
最新文章