C++算法练习-day19——18.四数之和

题目来源:. - 力扣(LeetCode)

题目思路分析

题目要求在给定的整数数组 nums 和一个目标值 target 中,找出所有独特的四元组(四个数),使得这四个数的和等于 target。需要注意的是,解集中的数字不能重复。

为了解决这个问题,我们可以采用一种优化的四数之和算法。具体思路如下:

  1. 排序:首先对数组进行排序,这有助于我们跳过重复的数字,并且可以使用双指针技术来减少时间复杂度。
  2. 固定前两个数:通过两层循环分别固定前两个数(记为 nums[a] 和 nums[b]),其中 a 从 0 遍历到 n-4(确保至少还有三个数可以选择),b 从 a+1 遍历到 n-3
  3. 跳过重复数字:在每层循环的开始,检查当前数字是否与上一个数字相同,如果是,则跳过,以避免重复的四元组。
  4. 提前终止:在固定 nums[a] 和 nums[b] 后,可以通过检查当前四个数的最小和与最大和是否满足目标值 target 来提前终止循环,从而减少不必要的计算。
    • 如果当前四个数的最小和(即 nums[a] + nums[a+1] + nums[a+2] + nums[a+3])大于 target,则无需继续遍历 b 及其后的数,因为后面的和会更大。
    • 如果当前四个数的最大和(即 nums[a] + nums[b] + nums[n-2] + nums[n-1],注意这里 b 还未固定到最大值)小于 target,则可以跳过当前的 a,直接检查下一个 a,因为即使 b 取最大值,和仍然小于 target
  5. 双指针寻找后两个数:对于固定的 nums[a] 和 nums[b],使用双指针 c 和 d 分别从 b+1 和数组末尾开始,向中间移动,寻找满足 nums[a] + nums[b] + nums[c] + nums[d] == target 的组合。
  6. 调整指针:如果当前和小于 target,则 c 向右移动;如果当前和大于 target,则 d 向左移动。
  7. 记录结果:每当找到一个满足条件的四元组时,将其添加到结果集中。

代码:

#include <vector>  
#include <algorithm>  
  
using namespace std;  
  
class Solution {  
public:  
    vector<vector<int>> fourSum(vector<int>& nums, int target) {  
        vector<vector<int>> ans;  
        int n = nums.size();  
        if (n < 4) {  
            return ans; // 如果数组长度小于4,无法找到四元组,直接返回空结果  
        }  
        sort(nums.begin(), nums.end()); // 对数组进行排序  
          
        // 固定前两个数  
        for (int a = 0; a < n - 3; ++a) {  
            // 跳过重复的数字  
            if (a > 0 && nums[a] == nums[a - 1]) {  
                continue;  
            }  
              
            // 提前终止:如果当前四个数的最小和大于target,则无需继续遍历  
            if ((long)nums[a] + nums[a + 1] + nums[a + 2] + nums[a + 3] > target) {  
                break;  
            }  
              
            // 提前终止:如果当前a能取到的最大和小于target,则跳过当前的a  
            if ((long)nums[a] + nums[n - 3] + nums[n - 2] + nums[n - 1] < target) {  
                continue;  
            }  
              
            for (int b = a + 1; b < n - 2; ++b) {  
                // 跳过重复的数字  
                if (b > a + 1 && nums[b] == nums[b - 1]) {  
                    continue;  
                }  
                  
                // 提前终止:如果当前四个数的最小和大于target,则无需继续遍历b及其后的数  
                if ((long)nums[a] + nums[b] + nums[b + 1] + nums[b + 2] > target) {  
                    break;  
                }  
                  
                // 提前终止:如果当前b能取到的最大和小于target,则跳过当前的b(但这里其实可以省略,因为外层a已经检查过了)  
                // 但为了保持逻辑完整性,还是保留了这个检查  
                if ((long)nums[a] + nums[b] + nums[n - 2] + nums[n - 1] < target) {  
                    continue;  
                }  
                  
                int d = n - 1; // 初始化右指针  
                // 固定第三个数,移动第四个数  
                for (int c = b + 1; c < n - 1; ++c) {  
                    // 跳过重复的数字  
                    if (c > b + 1 && nums[c] == nums[c - 1]) {  
                        continue;  
                    }  
                    long sum = (long)nums[a] + nums[b] + nums[c] + nums[d]; // 计算当前和  
                      
                    // 如果当前和大于目标值,移动右指针  
                    while (c < d && sum > target) {  
                        --d;  
                        sum = (long)nums[a] + nums[b] + nums[c] + nums[d]; // 更新当前和  
                    }  
                      
                    // 如果当前指针相遇,则无法再找到符合条件的四元组,跳出循环  
                    if (c == d) {  
                        break;  
                    }  
                      
                    // 如果找到符合条件的四元组,记录结果  
                    if (sum == target) {  
                        ans.push_back({nums[a], nums[b], nums[c], nums[d]});  
                    }  
                }  
            }  
        }  
        return ans; // 返回结果集  
    }  
};
知识点摘要
  1. 排序:排序是处理数组问题时的常用技巧,有助于跳过重复元素和使用双指针技术。
  2. 双指针:在处理三个或更多数的和问题时,双指针技术可以大大减少时间复杂度。
  3. 边界条件:在处理数组问题时,要特别注意数组长度、指针移动范围等边界条件。
  4. 跳过重复:在固定某些数时,通过检查当前数是否与上一个数相同来跳过重复的组合。
  5. 提前终止:通过检查当前四个数的最小和与最大和是否满足目标值 target 来提前终止循环,减少不必要的计算。

补充:用(long)转换四数之和的结果是为了防止四数之和超过int的范围 

四数之和问题是一个经典的算法问题,通过排序、双指针、跳过重复元素和提前终止等技巧,我们可以高效地解决这个问题。在本文中,我们详细分析了题目的思路,并给出了带有详细注释的代码实现。通过这些技巧,我们可以显著减少算法的时间复杂度,提高程序的运行效率。同时,这些技巧在处理其他类似的数组问题时也具有一定的参考价值。希望读者能够深入理解这些技巧,并在实际应用中灵活运用。

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

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

相关文章

Qt6.7.2中使用OpenSSL的坑

最近编写Qt Quick项目&#xff0c;使用Qt6.7.2版本&#xff0c;CMAKE编译&#xff0c;开始QtCreator运行代码都没有问题&#xff0c;访问https也正常&#xff0c;但打出安装包后一试&#xff0c;发现https访问不了&#xff0c;尴尬&#xff01;&#xff01; 查看了相关日志发现…

Flutter登录界面使用主题

Now, let’s use the theme we initially created in our main function for a simple login screen: 现在&#xff0c;让我们使用最初在主函数中创建的主题来制作一个简单的登录屏幕&#xff1a; Create a Login Screen Widget: Inside the main.dartfile, create a new wid…

尚硅谷 | Nginx | 学习笔记

尚硅谷 | Nginx | 学习笔记 尚硅谷Nginx教程由浅入深&#xff08;一套打通丨初学者也可掌握&#xff09;_哔哩哔哩_bilibili 文章目录 尚硅谷 | Nginx | 学习笔记一、Nginx相关概念1.Nginx是什么2.正向代理和反向代理正向代理反向代理 3.负载均衡和动静分离负载均衡动静分离 二…

[论文阅读]Detecting Pretraining Data from Large Language Models

Detecting Pretraining Data from Large Language Models http://arxiv.org/abs/2310.16789 这篇文章正式提出了Min-k%方法来实现成员推理攻击 贡献 介绍了WIKIMIA动态基准测试。旨在定期自动评估任何新发布的预训练 LLMs。通过利用 Wikipedia 数据时间戳和模型发布日期&am…

C#与C++交互开发系列(十三):在C#中使用C++编写的DLL,导出类的完整指南

前言 在跨平台和跨语言开发中,C++ 和 C# 的互操作性可以帮助我们实现更灵活且高性能的解决方案。C++ DLL 可以封装高效的算法或硬件相关的代码,而在 C# 中调用这些功能则可以大大简化开发。然而,由于 C++ 和 C# 的底层实现不同,导出 C++ 类并在 C# 中使用并不简单。因此,…

精选:HR招聘管理工具Top5使用体验

作为企业招聘者&#xff0c;如何在选择中找到开启高效招聘之门的钥匙&#xff0c;成为了每一位企业招聘管理者必须面对的难题&#xff0c;在面对市场上琳琅满目的招聘工具&#xff0c;你是否也曾感到无头绪&#xff0c;不知所措&#xff1f;每个工具都声称自己拥有独特的优势和…

python之多任务爬虫——线程、进程、协程的介绍与使用(16)

文章目录 1、什么是多任务?1.1 进程和线程的概念1.2 多线程与多进程的区别1.3 并发和并行2、python中的全局解释器锁3、多线程执行机制4、python中实现多线程(threading模块)4.1 模块介绍4.2 模块的使用5、python实现多进行程(Multiprocessing模块)5.1 导入模块5.2 模块的…

Kafka之消费者客户端

1、历史上的二个版本 与生产者客户端一样&#xff0c;在Kafka的发展过程当中&#xff0c;消费者客户端主要有两个大的版本&#xff1a; 旧消费者客户端&#xff08;Old Consumer&#xff09;&#xff1a;基于Scala语言开发的版本&#xff0c;又称为Scala消费者客户端。新消费…

Python 中的 @ 符号是如何工作的!

写在前面 Python 中的 符号是一个非常强大而又灵活的功能&#xff0c;它代表一个叫做"装饰器"的"语法糖"。在本文中&#xff0c;我们将一步步地了解它的工作原理&#xff0c;并通过示例代码加深理解。 基本概念 在 Python 中&#xff0c; 符号通常用于…

2024年9月电子学会青少年软件编程Python等级考试(三级)真题试卷

2024年9月青少年软件编程Python等级考试&#xff08;三级&#xff09;真题试卷 选择题 第 1 题 单选题 以下python表达式的值为True的是&#xff1f;&#xff08; &#xff09; A.all( ,1,2,3) B.any([]) C.bool(abc) D.divmod(6,0) 第 2 题 单选题 下列python代码的…

python项目实战——多协程下载美女图片

协程 文章目录 协程协程的优劣势什么是IO密集型任务特点示例与 CPU 密集型任务的对比处理 I/O 密集型任务的方式总结 创建并使用协程asyncio模块 创建协程函数运行协程函数asyncio.run(main())aiohttp模块调用aiohttp模块步骤 aiofiles————协程异步函数遇到的问题一 await …

【Linux系统编程】——探索Shell:工作原理与运行机制以及Linux的权限管理

文章目录 1. 什么是 Shell&#xff1f;2. Shell 的工作原理3. Shell 的运行机制4. Shell 的应用场景5. Shell 脚本的优缺点Linux权限的概念Linux权限管理文件权限值的表示方法文件访问权限的相关设置方法 目录的权限粘滞位关于权限的总结 1. 什么是 Shell&#xff1f; Shell 是…

Linux下的文件系统(进程与文件)

windows下的文件构成 .内容 .属性 所以&#xff0c; 文件的构成为内容和属性。 文件 内容 属性 推此即彼&#xff0c; linux下的文件构成也是如此。 liunx下&#xff0c;文件 文件的内核数据结构&#xff08;属性&#xff09;内容 深入理解c语言中的文件操作 在c语言中如…

【笔记】LLM位置编码之标准位置编码

标准位置编码 起源原理证明&#xff1a;对于任何固定的偏移量 k k k&#xff0c; P E p o s k PE_{posk} PEposk​可以表示为 P E p o s PE_{pos} PEpos​的线性函数。计算 P E p o s k 与 P E p o s PE_{posk} 与PE_{pos} PEposk​与PEpos​的内积结论 通俗理解缺点 起源 由…

论文笔记:LaDe: The First Comprehensive Last-mile Delivery Dataset from Industry

2023 KDD 1 intro 1.1 背景 随着城市化进程的加快和电子商务的发展&#xff0c;最后一公里配送已成为一个关键的研究领域 最后一公里配送&#xff0c;如图1所示&#xff0c;是指连接配送中心和客户的包裹运输过程&#xff0c;包括包裹的取件和配送除了对客户满意度至关重要外…

诺基亚的裁员风暴

大家好&#xff0c;我是鸭鸭&#xff01; 不知道 80、90 后还记得童年神机诺基亚吗&#xff1f; 虽然诺基亚早就把自家手机业务出售&#xff0c;但依然是一代通信巨头。 鸭鸭最近看到新闻&#xff0c;诺基亚已经在大中华区裁减了近 2000 名员工 。 根据 2023 年底&#xff0…

YOLOv8实战野生动物识别

本文采用YOLOv8作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv8以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对野生动物数据集进行训练和优化&#xff0c;该数据集包含丰富的野生动物图像样本…

9.Linux按键驱动-工作队列

1.思路 1.1在gpio结构体中定义工作队列 1.2 在probe函数中初始化工作队列 1.3.在中断服务程序中调度工作队列 1.4工作队列处理函数&#xff1a; 2.编程 程序&#xff1a; #include <linux/module.h> #include <linux/fs.h> #include <linux/errno.h> #…

C语言程序设计:现代设计方法习题笔记《chapter6》下篇

第七题 square3.c代码 #include<stdio.h>int main() { int i, n, odd, square;printf("This program prints a table of squares.\n");printf("Enter number of entries in table: ");scanf_s("%d", &n);i 1;odd 3;for (square 1;…

数据库课程 第一周

1.数据库的安装与卸载 1.1数据库的卸载&#xff1a; &#xff08;1&#xff09;第一种卸载方式&#xff1a;删除文件目录 &#xff08;2&#xff09;第二种卸载方式&#xff1a;在控制面版中卸载&#xff0c;然后在c盘里找到mysql文件删除 1. 2.在隐藏目录programdata里 1.2…