力扣第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 并且都为正数,后续元素只会更大,就可以提前结束当前循环,# 因为不可能存在四个数的和等于 targetif 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-1while left < right:# 计算选中的四个数之和ss = 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 += 1right -= 1#  四数之和小于目标值,需要将left指针向右移动elif s < target:left += 1# 四数之和大于目标值,为了减少和的大小# 需要将 right 指针向左移动,即向更小的数移动else:right -= 1return 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 += 1while left < right and nums[right] == nums[right-1]:right -= 1left += 1right -= 1elif s < target:left += 1else:right -= 1return 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.mzph.cn/news/821485.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为什么说日本茶道源于中国茶文化

茶&#xff0c;始于药&#xff0c;而后为饮茶&#xff0c;始于药&#xff0c;而后为饮。在8世纪的中国&#xff0c;茶就作为一桩雅事而进入一个诗意王国。而日本则在15世纪将其尊崇为一种美的宗教——茶道。 茶道&#xff0c;是在日常染污之间&#xff0c;因由对美的倾慕而建立…

redis五种类型介绍

Redis是一种内存数据存储系统&#xff0c;它支持五种不同的数据类型&#xff1a; 1. String String是Redis中最基本的数据类型&#xff0c;它可以存储任何形式的字符串数据&#xff0c;例如普通的文本字符串&#xff0c;二进制数据或JSON格式的数据。除此之外&#xff0c;还可以…

【ARM Trace32(劳特巴赫) 使用介绍 15 -- 通过 nRESE从CPU第一条指令开始Debug】

请阅读【嵌入式开发学习必备专栏 】 文章目录 Trace32 NRESETNRESET 作用nRESET 使用介绍JTAG 特定引脚控制CPU第一条指令开始进行 debug注意事项Trace32 NRESET 在 TRACE32 系统中,nRESET 是一个非常重要的概念,它直接关联到目标系统(通常是一个微处理器或微控制器)的硬件…

快手本地生活服务商入驻方法来了!超简单

本地生活市场正如一座蕴藏丰富的金矿&#xff0c;亟待我们去挖掘其潜在的价值。在2023年这个消费市场全面回暖的年份&#xff0c;服务零售行业的增速犹如一匹黑马&#xff0c;远远超过了商品零售。据权威数据显示&#xff0c;服务零售额的增长幅度高达20%&#xff0c;比商品消费…

前端开发框架BootStrap

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl BootStrap概述 Bootstrap是一个开源的前端框架&#xff0c;它由Twitter的设计师和开发者创建并维护。Bootstrap提供了许多现成的Web组件&#xff0c;可帮助开发者快速设计和…

Spring (四) 之配置及配置文件的操作

文章目录 1、Spring 基于注解的配置基于注解的配置引入依赖包配置实体类数据访问层业务层业务层实现测试 2、Bean和Component和Configuration的区别1 Bean:2 Component:3 Configuration:总结&#xff1a; 区别Component和Configuration区别 3、Spring读取properties配置文件准备…

第一届AI Agent智能体现场开发大赛报名开启!8月上旬火热开赛~

由联想拯救者、AIGC开放社区、英特尔携手主办的“AI生成未来第二届拯救者杯OPENAIGC开发者大赛”已经正式启动&#xff0c;“2024 AI Agent极限挑战赛”作为特设专项赛道&#xff0c;也将同步于8月上旬开赛&#xff0c;参赛者将在更加紧张刺激的现场比赛中展现其技术与创造力。…

Lua中文语言编程源码-第十节,更改ltm.c 元格操作函数, 使Lua加载中文库关键词(执行诸如__索引,__新索引,__加等元表操作)

源码已经更新在CSDN的码库里&#xff1a; git clone https://gitcode.com/funsion/CLua.git 在src文件夹下的ltm.c 表格操作函数&#xff0c;此模块是C语言编写的&#xff0c;是Lua语言中的一个库文件&#xff0c;主要用来提供元表操作的功能。 该库提供了许多函数&#xff…

抖音小店新店铺起飞式玩法,这几步一定要做好,前期很重要

大家好&#xff0c;我是电商笨笨熊 进入抖音小店后不知道该怎么操作&#xff0c;不清楚如何让新店快速起店&#xff1b; 今天我们就来聊聊新店铺快速起店的几个关键步骤&#xff0c;新手玩家一定要按照流程去做。 第一步&#xff1a;店铺搭建 小店开通之后不要着急选品上架&…

OpenAI 选择东京作为其首个亚洲办事处

新办事处旨在促进与日本政府、当地企业和研究机构的合作&#xff0c;开发适合日本独特需求的人工智能工具。 之所以选择东京作为OpenAI在亚洲的第一家企业&#xff0c;是因为这里拥有全球领先的技术、致力于服务的文化和创新的社区。 "OpenAI 首席执行官 Sam Altman 解释…

MGRE环境下的ospf实验

MGRE环境下的ospf实验 一.拓扑图 二.实验步骤 1.分配各路由网段IP [R1]int g 0/0/0 [R1-GigabitEthernet0/0/0]ip address 16.0.0.1 24 [R1-GigabitEthernet0/0/0]int g 0/0/1 [R1-GigabitEthernet0/0/1]ip address 116.0.0.1 24[R2]int g 0/0/0 [R2-GigabitEthernet0/0/0]…

Docker+Uwsgi部署Django项目

在之前的文章中&#xff0c;已经给大家分享了在docker中使用django自带的命令部署项目&#xff0c;这篇文章主要讲解如何使用uwsgi部署。 1. 在Django项目的根目录下新建Dockerfile文件 #Dockerfile文件 # 使用 Python 3.9 作为基础镜像 FROM python:3.9# 设置工作目录 WORKDI…

static辨析

静态变量 局部全局非静态局部作用域&#xff0c;只在函数执行期间存在全局作用域&#xff0c;作用域为所有的源文件&#xff0c;但是在其他不包含全局变量定义的源文件中需要用extern关键字再次声明静态局部作用域&#xff0c;只被初始化一次&#xff0c;自从第一次被初始化直…

随机游走的艺术-图嵌入表示学习

图嵌入引入 机器学习算法&#xff1a; 厨师 样本集&#xff1a; 食材 只有好的食材才能做出好的饭菜 我们需要把数据变成计算机能够读懂的形式&#xff08;将数据映射成为向量&#xff09; 图嵌入概述 传统图机器学习 图表示学习 自动学习特征&#xff0c;将…

初学python记录:力扣924. 尽量减少恶意软件的传播

题目&#xff1a; 给出了一个由 n 个节点组成的网络&#xff0c;用 n n 个邻接矩阵图 graph 表示。在节点网络中&#xff0c;当 graph[i][j] 1 时&#xff0c;表示节点 i 能够直接连接到另一个节点 j。 一些节点 initial 最初被恶意软件感染。只要两个节点直接连接&#x…

提升测试效率都有哪些具体手段?

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

uncloud的查询数据库的条件要和shema中写的一致,不然会报错

为什么uni-app中的database中的有些文件在hbuilder中可以看到&#xff0c;在vscode中看不到&#xff1f; uni-starter微信登录后查数据库db.collection后会提示没有权限 貌似非管理员都不能访问 uni-starter微信登录后查数据库db.collection(opendb-poi).aggregate()后会提示…

计算机网络(六)应用层

应用层 基本概念 服务器端&#xff08;Server&#xff09;&#xff1a; 服务器是网络中提供服务的计算机或软件程序。服务器通常具有更高的性能、更大的存储空间和更高的带宽&#xff0c;用于提供各种服务&#xff0c;如文件存储、数据库管理、Web托管、电子邮件传递等。服务…

什么是主数据?

主数据定义 主数据指满足组织跨部门业务协同需要的、反映核心业务实体状态属性的基础信息。主数据具有以下特征: (1)跨越部门:主数据是满足跨部门业务协同需要的&#xff0c;是各个部门在开展业务过程中都需要的数据&#xff0c;是所有部门及其业务过程的“最大公约数据”: …

共享桌面,3分钟自己实现一个吧,还能听见麦克风声音哦

前言 关于【SSD系列】&#xff1a; 前端一些有意思的内容&#xff0c;旨在3-10分钟里&#xff0c; 500-1000字&#xff0c;有所获&#xff0c;又不为所累。 共享桌面程序&#xff0c;哇&#xff0c;高大尚耶&#xff01;其实不然&#xff0c;让我带你3分钟实现桌面共享程序&am…