C语言编程--15.四数之和

news2025/4/25 14:51:42

题目:

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  1. 0 <= a, b, c, d < n
  2. a、b、c 和 d 互不相同
  3. 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]]

提示:

1 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109

代码:

#include <stdlib.h>

// 比较函数,用于 qsort 对数组进行排序
// pa 和 pb 是指向要比较元素的指针
// 返回值为 1 表示 a > b,返回 -1 表示 a < b
int cmp(const void* pa, const void* pb)
{
    int a = *(int*)pa;  // 将 pa 指针指向的元素转换为 int 类型并赋值给 a
    int b = *(int*)pb;  // 将 pb 指针指向的元素转换为 int 类型并赋值给 b
    return a > b ? 1 : -1;  // 如果 a 大于 b 返回 1,否则返回 -1
}

// 四数之和函数,用于找出数组中所有不重复的四元组,使得它们的和等于目标值
// nums 是输入的整数数组
// numsSize 是数组的长度
// target 是目标和
// returnSize 是返回的四元组的数量
// returnColumnSizes 是每个四元组的长度(固定为 4)
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes) {
    qsort(nums, numsSize, sizeof(int), cmp);  // 对数组进行排序,方便后续去重和双指针操作
    int base = 100;  // 初始分配的结果数组的容量
    int **result = (int**)malloc(sizeof(int*) * base);  // 动态分配存储四元组的二维数组
    *returnColumnSizes = (int*)malloc(sizeof(int) * base);  // 动态分配存储每个四元组长度的数组
    *returnSize = 0;  // 初始化返回的四元组数量为 0

    // 如果数组长度小于 4,直接返回空结果
    if (numsSize < 4) {
        return result;
    }

    // 外层循环,固定第一个数
    for(int i = 0; i < numsSize - 3; i++) {
        // 跳过重复的第一个数,避免结果中出现重复的四元组
        if (i > 0 && nums[i] == nums[i - 1])
            continue;

        // 第二层循环,固定第二个数
        for(int j = i + 1; j < numsSize - 2; j++) {
            // 跳过重复的第二个数,避免结果中出现重复的四元组
            if (j > i + 1 && nums[j] == nums[j - 1])
                continue;

            int l = j + 1;  // 左指针,指向第二个数的下一个位置
            int r = numsSize - 1;  // 右指针,指向数组的最后一个位置

            // 双指针法,在剩余的元素中寻找满足条件的第三个数和第四个数
            while (l < r) {
                // 计算四个数的和,使用 long long 类型避免整数溢出
                long long sum = (long long)nums[i] + (long long)nums[j] + (long long)nums[l] + (long long)nums[r];
                long long temp = sum - target;  // 计算当前和与目标值的差值

                // 如果差值为 0,说明找到了一个满足条件的四元组
                if (temp == 0) {
                    result[*returnSize] = (int*)malloc(sizeof(int) * 4);  // 为新的四元组分配内存
                    (*returnColumnSizes)[*returnSize] = 4;  // 设置该四元组的长度为 4
                    result[*returnSize][0] = nums[i];  // 存储第一个数
                    result[*returnSize][1] = nums[j];  // 存储第二个数
                    result[*returnSize][2] = nums[l];  // 存储第三个数
                    result[*returnSize][3] = nums[r];  // 存储第四个数
                    (*returnSize)++;  // 四元组数量加 1

                    // 如果结果数组的容量不够,扩大容量
                    if (*returnSize == base) {
                        base *= 2;  // 容量翻倍
                        result = (int**)realloc(result, sizeof(int*) * base);  // 重新分配结果数组的内存
                        *returnColumnSizes = (int*)realloc(*returnColumnSizes, sizeof(int) * base);  // 重新分配每个四元组长度数组的内存
                    }

                    int a = nums[l];  // 记录当前左指针指向的数
                    int b = nums[r];  // 记录当前右指针指向的数

                    // 跳过重复的第三个数
                    while (nums[l] == a && l < r)
                        l++;
                    // 跳过重复的第四个数
                    while (nums[r] == b && l < r)
                        r--;
                } 
                // 如果当前和大于目标值,右指针左移
                else if (temp > 0) {
                    r--;
                } 
                // 如果当前和小于目标值,左指针右移
                else {
                    l++;
                }   
            }
        }
    }
    return result;  // 返回存储所有满足条件四元组的二维数组
}

代码分析:

优点

  1. 排序和双指针法:通过对数组进行排序,然后使用双指针法,将原本的暴力枚举 O(n4)的时间复杂度降低到了O(n3),提高了算法的效率。
  2. 去重处理:在每一层循环中都进行了去重处理,避免了结果中出现重复的四元组,保证了结果的正确性。
  3. 动态内存分配:使用 malloc 和 realloc 动态分配内存,根据实际结果的数量调整内存大小,避免了内存的浪费。
  4. 处理整数溢出:在计算四个数的和时,使用 long long 类型,避免了整数溢出的问题,提高了代码的健壮性。

缺点

  1. 时间复杂度较高:虽然使用了双指针法将时间复杂度从 O(n4)的时间复杂度降低到了O(n3),但对于大规模数据,仍然可能会超时。
  2. 内存管理复杂:使用了动态内存分配,需要手动管理内存,容易出现内存泄漏的问题。在使用完返回的结果数组后,需要调用者手动释放内存。
  3. 提前剪枝不足:代码中虽然有一些基本的逻辑,但没有充分利用排序后的数组特性进行更有效的提前剪枝,例如可以在某些情况下提前终止循环,减少不必要的计算。

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

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

相关文章

HTML、XHTML 和 XML区别

HTML、XHTML 和 XML 这三兄弟的区别 HTML: 老大哥,负责网页长啥样,性格比较随和,有点小错误也能容忍。XHTML: 二哥,看着像 HTML,但规矩严,是按 XML 的规矩来的 HTML,更规范。XML: 小弟,负责存储和传输数据,非常灵活,标签可以自己随便定,但规矩最严。它们仨长啥样?(…

FPGA上实现YOLOv5的一般过程

在FPGA上实现YOLOv5 YOLO算法现在被工业界广泛的应用&#xff0c;虽说现在有很多的NPU供我们使用&#xff0c;但是我们为了自己去实现一个NPU所以在本文中去实现了一个可以在FPGA上运行的YOLOv5。 YOLOv5的开源代码链接为 https://github.com/ultralytics/yolov5 为了在FPGA中…

4U带屏基于DSP/ARM+FPGA+AI的电力故障录波装置设计方案,支持全国产化

4U带屏DSP/ARMFPGAAI电力故障录波分析仪&#xff0c;支持国产化&#xff0c;含有CPU主控模块&#xff0c;96路模拟量采集&#xff0c;256路开关量&#xff0c;通讯扩展卡等#电力故障录波#4U带屏#新能源#电力监测 主要特点 1&#xff09;是采用嵌入式图形系统&#xff0c;以及…

数据库数据删除与修改实验

数据库数据删除与修改实验 在数据库原理的学习中&#xff0c;数据的删除与修改是核心操作技能。通过“删除修改数据”实验&#xff0c;我系统实践了 SQL 中 UPDATE 和 DELETE 语句的多种应用场景&#xff0c;从基础语法到复杂业务逻辑处理&#xff0c;积累了丰富的实战经验。本…

【含文档+PPT+源码】基于SpringBoot+vue的疫苗接种系统的设计与实现

项目介绍 本课程演示的是一款 基于SpringBootvue的疫苗接种系统的设计与实现&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系…

项目自动化测试

一.设计测试用例(细致全面) 二.先引入所需要的pom.xml依赖 1.selenium依赖 2.webdrivermanager依赖 3.commons-io依赖 编写测试用例–按照页面对用例进行划分,每个页面是Java文件,页面下的所有用例统一管理 三.common包(放入公用包) 类1utils 可以调用driver对象,访问url …

Python爬虫爬取图片并存储到MongoDB(注意:仅尝试存储一条空的示例数据到MongoDB,验证MongoDB的联通性)

以下是一个使用Python爬取图片并存储到MongoDB的示例实现&#xff0c;包含详细步骤说明&#xff1a; import requests from bs4 import BeautifulSoup from pymongo import MongoClient from datetime import datetime import os import re# 配置信息 mongoIP mongodb://root…

L1-1、Prompt 是什么?为什么它能“控制 AI”?

*Prompt 入门 L1-1 想象一下&#xff0c;你只需输入一句话&#xff0c;AI 就能自动为你写一篇文案、生成一份报告、甚至规划你的创业计划。这种“对话即编程”的背后魔法&#xff0c;就是 Prompt 的力量。 &#x1f50d; 一、Prompt 的定义与由来 Prompt&#xff08;提示词&am…

TIM输入捕获知识部分

越往左&#xff0c;频率越高&#xff1b;越往右&#xff0c;频率越低。【越紧凑&#xff0c;相同时间&#xff0c;次数越多】 计算频率的方法&#xff1a;测评法、测周法、中界频率。 频率的定义&#xff1a;1s内出现了多少个重复的周期 测评法就是从频率的定义出发的&#…

PCB常见封装类型

1. 电阻、电容、电感封装 2. 二极管、三极管封 3. 排阻类器件&#xff08;8脚、16脚&#xff09;封装 4. SO类器件&#xff08;间距有1.27、2.54mm等&#xff09;封装 5. QFP类器件封装&#xff08;四方扁平封装&#xff09; 结构&#xff1a;引脚分布在封装的四个侧面&#…

【Linux】调试工具gdb的认识和使用指令介绍(图文详解)

目录 1、debug和release的知识 2、gdb的使用和常用指令介绍&#xff1a; &#xff08;1&#xff09;、windows下调试的功能&#xff1a; &#xff08;2&#xff09;、进入和退出&#xff1a; &#xff08;3&#xff09;、调试过程中的相关指令&#xff1a; 3、调试究竟是在…

UML设计系列(9):开发过程中如何应用UML

传送门 UML设计系列(1)&#xff1a;状态机图 UML设计系列(2)&#xff1a;类图 UML设计系列(3)&#xff1a;时序图 UML设计系列(4)&#xff1a;用例图 UML设计系列(5)&#xff1a;系统依赖图 UML设计系列(6)&#xff1a;活动图 UML设计系列(7)&#xff1a;UML设计阶段性总…

模板方法模式:定义算法骨架的设计模式

模板方法模式&#xff1a;定义算法骨架的设计模式 一、模式核心&#xff1a;模板方法定义算法骨架&#xff0c;具体步骤延迟到子类实现 在软件开发中&#xff0c;经常会遇到这样的情况&#xff1a;某个算法的步骤是固定的&#xff0c;但具体步骤的实现可能因不同情况而有所不…

通付盾入选苏州市网络和数据安全免费体验目录,引领企业安全能力跃升

近日&#xff0c;苏州市网络安全主管部门正式发布《苏州市网络和数据安全免费体验产品和服务目录》&#xff0c;通付盾凭借其在数据安全、区块链、AI领域的创新实践和前沿技术实力&#xff0c;成功入选该目录。 作为苏州市网络安全技术支撑单位&#xff0c;通付盾将通过 “免费…

【金仓数据库征文】加速数字化转型:金仓数据库在金融与能源领域强势崛起

目录 一、引言 二、金仓数据库&#xff08;KingbaseES&#xff09;概述 1. 发展历程与市场地位 2. 核心技术架构 3. 金仓数据库的特点 三、金仓数据库在金融行业的应用 1. 金融行业的挑战与需求 2. 金仓数据库在金融行业的优势 3. 金仓数据库在金融行业的实际应用案例 …

C++智能指针上

一、裸指针 “裸指针”是最基础的&#xff0c;直接存储内存地址的指针类型。特点&#xff1a;①它本身没有自动的内存管理机制&#xff1a;如它不会自动释放内存&#xff0c;也不会检查是否指向有效的内存区域&#xff1b;②直接操作内存地址&#xff0c;不进行任何的边界检查&…

低代码平台开发串口调试助手

项目介绍 串口调试助手是一款用于串口通信调试的工具&#xff0c;它可以帮助开发人员发送和接收串口数据&#xff0c;主要用于嵌入式开发、工业控制、物联网设备开发等领域。 主要功能包括&#xff1a; 数据收发&#xff1a;可以实时发送和接收串口数据&#xff0c;并显示在界…

怎么配置一个kubectl客户端访问多个k8s集群

怎么配置一个kubectl客户端访问多个k8s集群 为什么有的客户端用token也访问不了k8s集群&#xff0c;因为有的是把~/.kube/config文件&#xff0c;改为了~/.kube/.config文件&#xff0c;文件设置成隐藏文件了。 按照kubectl的寻找配置的逻辑&#xff0c;kubectl找不到要访问集群…

12N60-ASEMI无人机专用功率器件12N60

编辑&#xff1a;LL 12N60-ASEMI无人机专用功率器件12N60 型号&#xff1a;12N60 品牌&#xff1a;ASEMI 封装&#xff1a;TO-220F 最大漏源电流&#xff1a;12A 漏源击穿电压&#xff1a;600V 批号&#xff1a;最新 RDS&#xff08;ON&#xff09;Max&#xff1a;0.68…

长城智驾重复造轮子

左手新能源&#xff0c;右手智驾&#xff0c;这是长城当下最在意的两块业务。 从去年8月首款具备高阶智能驾驶功能SUV全新蓝山上市之后&#xff0c;长城在传播端的重点就是围绕智驾、无图方案打造智驾标签。 先是在广州国际车展上&#xff0c;整个展厅只展出全新蓝山&#xf…