C语言好题分享七(三数之和)

news2024/11/24 10:14:18

❀❀❀ 文章由@不准备秃的大伟原创 ❀❀❀

♪♪♪ 若有转载,请联系博主哦~ ♪♪♪

❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤

   三数之和

  题目来源LeetCode:刷题传送门

  题目:给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。

请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

c9c7464be3304d1abf8577f84d5aa562.png

  由题目可以得到我们呢需要求的是一个数组内的三个和为0的元素,且需要是不同的三个元素。

  其实当我们进去做题目的时候会发现提干处会有如下一段英文

/*

 * Return an array of arrays of size *returnSize.

 * The sizes of the arrays are returned as *returnColumnSizes array.

 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().

 */

简单翻译一下就是: 

返回一个大小为 *returnSize 的数组,数组中的每个元素都是一个数组。

  • 数组的大小作为 *returnColumnSizes 数组返回。

  • 注意:返回的数组和 *columnSizes 数组都必须使用 malloc 进行分配内存,假设调用者会调用 free() 进行释放。

         在C语言中我们不仅要实现代码,还需要考虑*returnSize和*returnColumnSize的开辟,这一点其实是在做题时C比其他语言要繁琐的地方

        算法一:暴力求解

  同样的我们先来最简单也最容易想到的暴力求解:使用三个for循环一个一个找:(伪代码实现)

//由于这段代码有很多的细节没有考虑,所以暂时就先不管returnSize和returnColumnSize的开辟了
int** ans = malloc(sizeof(int*)*numsSize)
for(int i = 0; i < numsSize - 2; i++){
    for(int j = i + 1; j < numsSize - 1; j++){
        for(int k = numsSize - 1; k > 1; k--){
ans[*returnSize][0] =nums[i];//ans为一个二维数组
ans[*returnSize][1] =nums[j];
ans[*returnSize][2] =nums[k];
(*returnSize++);
//如果满足ans[i] + ans[j] + ans[k] == 0 则存入ans里
}
}
}
return ans;

        这一种方法很笨,但是也很容易想到,时间复杂度是O(N*N*N)。

        那我们来想一想这一段代码除了没有考虑returnSize的returnColumnSize的开辟,其他有没有什么别的问题?

        是的,聪明且细心的铁汁一定发现了,题目要求:不同的三元组,所以我们还需要写一段代码判断是否有重复的答案存在。

        好的,到这里铁汁们是不是头都要秃了啊?○( ^皿^)っHiahiahia…  那这样,我们先来看一条类似的但更简单的题目:

        两数之和

  题目来源LeetCode:刷题传送门

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

5d495dbf2acc4c1c8a4e250248b60bf9.png 

/**

 * Note: The returned array must be malloced, assume caller calls free().

 */

 返回的答案必须使用 malloc 进行分配内存,假设调用者会调用 free() 进行释放。

  思想一:暴力求解

        太简单了,所以博主直接放代码了:

int* twoSum(int* nums, int numsSize, int target, int* returnSize)
{
   for(int i = 0; i < numsSize; i++)
   {
       for(int j = i + 1; j < numsSize; j++)
       {
           if(nums[i] + nums[j] == target)
           {
          *returnSize = 2;
                int* ans = (int*)malloc(sizeof(int) * 2);
                ans[0] = i; ans[1] = j; 
                return ans;
           }
       }
   } 
   *returnSize = 0;
   return NULL;
}

  思想二:排序+双指针

  看过博主上一篇好题分享的铁汁们应该对双指针有所了解了,其实在熟练掌握了排序+双指针之后像这种类似的题目的第一个想法就应该是双指针了。

  两数之和比三数之和简单的原因不仅是数字变少了,而且最终的答案也只有一组解,不需要考虑去重,需要开辟的空间内容也少了。

        不知道铁汁们还记不记得上一次的双指针思路了,不记得的话....:--->盛水最多的容器

    好的,我们大概回顾一下哈~:我们所谓的双指针呢,不是真的指针,而是用两个数来表示数组的下标,一般一个指向第一个元素,一个指向最后一个元素,在不同的情况下对两个数进行不同的操作。 

        嗯...怎么说呢,这道题想到双指针本身是很好的想法,但是我们答案需要我们返回的是元素下标,所以如果我们使用qsort排序后,下标就会被打乱,这样返回的答案就会有错误。 那如果我们改一下,最后的答案求的是两个值,那么双指针就是嘎嘎棒了!

        虽然求两个数的和我们不可以用双指针,但是我们可以把思维套用到求三个数的和的那个题目上:

三数之和の思想二:排序+双指针

        首先我们先把nums排个序,因为我们的方法是以排序为起点的嘛:

 int cmp(const int* p1,const int* p2)
 {
     return *p1 - *p2;
 }
//函数内
qsort(nums,numsSize,sizeof(int),cmp);

        首先我们先实现代码的主体:不管怎么说,实现题目的需求才是第一重要嘛:

int j = 0;//这里引用一个变量j,表示的答案有多少个,即returnSize,所以只要最后=一下就可以了 
int left = 0;
    int right = i - 1;
    while(left < right)
    {
        if(nums[left] + nums[right] + nums[i] == 0) {
         ans[j] = (int*)malloc(sizeof(int) * 3);
        ans[j][0] = nums[left];
        ans[j][1] = nums[right];
        ans[j][2] = nums[i];
        j++;
        left++;
        right--;
    }
        else if(nums[left] + nums[right] + nums[i] > 0)
        right--;
        else
        left++;

        好,上面我们已经实现了主体,接下来我们需要考虑*reuturnSize和*returnColumnSize 内存的开辟:但是~先别急,我们在写答案的时候如果没有可以返回的答案能行吗? 当然不行了啊,所以呢,在考虑其他细节之前,我们要把答案存到一个二维数组里面啊!

    int** ans = malloc(sizeof(int*)*numsSize*numsSize);
//行
    ans[j][0] = nums[left];
    ans[j][1] = nums[right];
    ans[j][2] = nums[i];
//三列,在暴力求解里已经写过了

      这时候会有铁汁问了:“博主啊,你这个**ans为什么开辟了个numsSize*numsSize*sizeof(int) 大小的空间啊?” ,问得好,其实我们可以想象一下:

  三个数和为0,当其中一个数变化,其他一个或者两个数肯定会变化的,而我们考虑最坏的情况,每次三个数只动两个数就可以满足和为0,那这是不是就类似两个 变量的循环,复杂度为O(N*N),最后不也就是numsSize*numsSize*sizeof(int) ?

  但我们毕竟不能准确的计算需要的空间,开辟的大一点以防止越界。

   接下来我们考虑*reuturnSize和*returnColumnSize 内存的开辟:由函数主体可以得到j就是*returnSize,所以不知不觉中我们就把他的值给算出来了,而*returnColumnSize就比较麻烦了:

*returnColumnSizes = (int*)malloc(numsSize * numsSize *sizeof(int));
//行(同样的,开辟大一点没什么不好)
(*returnColumnSizes)[j] = 3;
//列(可以直接放在while循环内,每一行就是3个元素)
*returnSize = j;

  这时候我们的代码就基本写好了,然后会有铁汁迫不及待的点个提交,然后“啪”的一下显示个错误,然后又回来骂博主了:“你这教的啥,都错的!”        

  诶诶诶,别啥事都赖我啊o(TヘTo) , 还亏我在文章开头夸你呢!现在我又得骂你记性不好了!  (┬_┬)↘ 

  忘了吧?是不是忘了?忘了去重了吧?!

  其实实现去重也是比较简单的:

4cdb154705b542d5b6a606151ed44a07.png

  但是又有一个问题了:如果我们的案例是{0,0,0,0}的话不就会越界吗?所以我们还需要加个判断条件,代码实现如下:

while(left < right && nums[left] == nums[left + 1]) left++;
        while(right > left && nums[right] == nums[right - 1]) right--;
//千万记住left < right要放在==前面,因为&&的短路性质,当前面条件不成立的时候,就不会判断后面的条件,所以也就不会报错

   最后我们只需要return ans;就可以完成我们的代码了,展示一下自己的成果吧:

int cmp(const int* p1,const int* p2)
 {
     return *p1 - *p2;
 }
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
    qsort(nums,numsSize,sizeof(int),cmp);
    int** ans = malloc(sizeof(int*)*numsSize*numsSize);
    *returnColumnSizes = (int*)malloc(numsSize * numsSize *sizeof(int));
    int j = 0;
for(int i = numsSize - 1; i > 1; i--)
{
    if(i < numsSize -1 && nums[i] == nums[i + 1]) continue;
        int left = 0;
    int right = i - 1;
    while(left < right)
    {
        if(nums[left] + nums[right] + nums[i] == 0) {
         (*returnColumnSizes)[j] = 3;
         ans[j] = (int*)malloc(sizeof(int) * 3);
        ans[j][0] = nums[left];
        ans[j][1] = nums[right];
        ans[j][2] = nums[i];
        j++;
                while(left < right && nums[left] == nums[left + 1]) left++;
        while(right > left && nums[right] == nums[right - 1]) right--;
        left++;
        right--;
        }
        else if(nums[left] + nums[right] + nums[i] > 0)
        right--;
        else
        left++;
    }
}
*returnSize = j;
return ans;

}

  然后提交,通过!b2468ef9694a48228dc5c904e2693dbf.png 

  这一路走下来真的很艰辛啊,但是无论什么道路都不会是轻松的,而且这也是我们成长的必经之路啊!但其实我们回过头来再仔细看看,想一想,这其实也没什么,当我们会这么觉得的时候,你已经成长了!

  由于再过几天全国各大高校都要举行四六级考试了,博主在这里祝各位学子(当然包括博自己了)四六级一举通过! 绩点刷满!期末永不挂科!

  那么本篇博客也就到此为止了,给大家送上个祝福,勉励自己以及这世界上所有追逐梦想的赤子趁年华尚好努力提升自己,莫欺少年穷!(看博主这么诚心诚意,给个赞不过分吧!ヾ(^▽^*))) )

22f93c7c787343e4a35d32ae8a9cc148.jpeg

 

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

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

相关文章

24V降12V2A同步降压芯片WT6023A

24V降12V2A同步降压芯片WT6023A 今天给大家带来一款高性能的DC/DC转换器WT6023A&#xff0c;快来一起了解一下吧&#xff01; WT6023A是一款采用抖动频率模式控制架构的高效、单片同步降压型DC/DC转换器&#xff0c;能够提供高达6A的连续负载&#xff0c;具有出色的线路和负载…

V友故事·感恩节特辑|Vol.7 用 EasyV 开启不受限的可视化设计体验

本期嘉宾 张啸天&#xff08;站酷 ID&#xff1a;张张张夏天&#xff09;&#xff0c;从事设计行业已经 4 年多&#xff0c;接触可视化设计工作大概有 2 年时间。目前就职于卓见云的可视化业务部门&#xff0c;所在团队大概 15 人左右&#xff0c;包含了产品、设计、开发、引擎…

中科驭数作为战略合作伙伴受邀出席2023首都在线业务发布会 共谋多元算力产业生态

近日&#xff0c;赋能算力与场景的联接暨2023首都在线业务发布会在北京召开&#xff0c;中科驭数作为首都在线战略合作伙伴&#xff0c;受邀出席本次发布会&#xff0c;发表《DPU赋能新型算力基础设施》主题演讲&#xff0c;并联合参与多元算力产业生态联盟发布仪式&#xff0c…

会 C# 应该怎么学习 C++?

会 C# 应该怎么学习 C&#xff1f; 在开始前我有一些资料&#xff0c;是我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心整理了一份「C的资料从专业入门到高级教程工具包」&#xff0c;点个关注&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&a…

CentOS 7部署Gitlab:强大的代码管理和团队协作工具

文章目录 &#xff08;1&#xff09;介绍&#xff08;2&#xff09;Gitlab下载&#xff08;3&#xff09;安装Gitlab&#xff08;4&#xff09;修改Gitlab配置文件&#xff08;5&#xff09;Gitlab常用命令&#xff08;6&#xff09;设置存储路径&#xff08;7&#xff09;修改…

使用Microsoft Dynamics AX 2012 - 8. 财务管理

财务管理的主要职责是控制和分析与货币金额有关的所有交易。这些事务发生在整个组织的业务流程中。 因此&#xff0c;财务管理是企业管理解决方案的核心领域。在Dynamics AX中&#xff0c;支持所有部门业务流程的应用程序的深度集成可立即提供准确的财务数据。 分类账交易的原…

多窗口文件管理工具Q-Dir安装以及使用教程

软件介绍 Q-Dir 是一款功能强大的Windows资源管理器&#xff0c;可以非常方便的管理你的各种文件。Q-Dir有4 个窗口&#xff0c;特别适用于频繁在各个目录间跳跃复制粘贴的情况&#xff0c;每个窗口都可以方便的切换目录&#xff0c;以不同颜色区分不同类型的文件&#xff0c;…

【后端学前端】第三天 css动画 动态搜索框(定位、动态设置宽度)

1、学习信息 视频地址&#xff1a;css动画 动态搜索框&#xff08;定位、动态设置宽度&#xff09;_哔哩哔哩_bilibili 2、源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>test3</title>…

Debian 系统镜像下载

最近在看一些网络相关的文章需要用到 debian 11.x 的系统网上找了好多都发下载&#xff0c;在官网看一下 有个 11.8 的版本我无法下载&#xff0c;提示被最新的 debian-12.4.0 所代替&#xff0c;于是找到了这个链接 Index of /cdimage/unofficial/non-free/cd-including-fi…

2023年好用的构建电子商务知识库软件推荐

随着电子商务的飞速发展&#xff0c;构建一个高效、精准的电子商务知识库软件成为了众多企业的迫切需求。为了帮助企业在浩如烟海的信息中迅速找到所需知识&#xff0c;提升运营效率&#xff0c;今天就推荐几款不错的电子商务知识库软件。 | 1、HelpLook HelpLook是一款零代码…

盲盒小程序如何盈利?创业新模式

当前&#xff0c;盲盒的影响力越来越大&#xff0c;深受年轻人的热爱&#xff0c;受众群体逐渐增加&#xff0c;盲盒的市场规模不断扩大。 在当下社交媒体时代&#xff0c;盲盒也转到了互联网上&#xff0c;根据网络的传播&#xff0c;盲盒也迎来了新一轮的发展&#xff0c;“…

vue3使用mars3d实现地图轮播高亮,且每个区域颜色不一样

效果图(珙县就是轮播高亮的效果) 思路:初始化一张完整的地图&#xff0c;然后定时器去挨个生成每个县上的地图&#xff0c;并且覆盖在原来的位置&#xff0c;每到一定的时间&#xff0c;就清除之前生成高亮图并且生成下一张高亮图 如何引入地图 上篇文章已详细发过 略 父组…

在发布应用程序内测时如何选择合适的分发上架方式?

在现代移动互联网的环境下&#xff0c;应用已经成为人们生活不可或缺的一部分&#xff0c;选择合适的分发方式对于应用的发展和成功来说至关重要。不同的分发方式有着自己的特点和优缺点&#xff0c;所以需要针对性地进行选择。下面分享一些我个人理解的选择合适的分发需要哪些…

temu哪里可以看到买手信息

在拼多多跨境电商平台Temu上查看买手信息是一项非常重要的任务&#xff0c;因为买手是您在平台上购买商品的关键人物。通过查看买手信息&#xff0c;您可以了解买手的信誉、服务质量以及其他用户对其的评价。本文将为您介绍如何在Temu上查看买手信息&#xff0c;并提供一些建议…

如何用gpt改写文章 (1) 神码ai

大家好&#xff0c;今天来聊聊如何用gpt改写文章 (1)&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff1a; 如何用GPT改写文章 一、引言 随着人工智能技术的飞速发展&#xff0c;自然语言处理领域取得了重大突…

解题方式篇-回溯

回溯算法 1、简介 简介&#xff1a;回溯法也可以叫做回溯搜索法&#xff0c;它是一种搜索的方式。 回溯是递归的副产品&#xff0c;只要有递归就会有回溯。回溯是一种暴力的搜索方式。 回溯法&#xff0c;一般可以解决如下几种问题&#xff1a;组合&#xff08;无序&#xff0…

Spring Boot 3.x.x Spring Security 6.x.x @PreAuthorize 失效

Spring Boot 3.x.x Spring Security 6.x.x PreAuthorize 失效 背景问题解决备注 背景 最近在搞一个后端项目&#xff0c;登录、接口权限、token认证。 版本 Spring Boot 3.2.0 JDK 21 Spring Security 6.2.0 问题 PreAuthorize 失效&#xff0c;没有走认证。 解决 给PreAu…

SD-WAN可以加速视频会议吗?

在企业对远程办公和视频会议的需求越来越多的背景下&#xff0c;网络连接的速度和稳定性对于确保视频会议的顺利进行变得至关重要。那么&#xff0c;SD-WAN组网作为一种网络优化方案&#xff0c;它可以加速视频会议吗&#xff1f; SD-WAN加速的原理在于通过优化网络传输路径和减…

深度学习 | 前馈神经网络与反向传播算法

目录 一、Logistic函数 二、前馈神经网络&#xff08;FNN&#xff09; 三、反向传播算法&#xff08;BP算法&#xff09; ​四、基于前馈神经网络的手写体数字识别 一、Logistic函数 Logistic函数是学习前馈神经网络的基础。所以在介绍前馈神经网络之前&#xff0c;我们首…

RHEL8_Linux使用podman管理容器

本章主要介绍使用 podman 管理容器 了解什么是容器&#xff0c;容器和镜像的关系安装和配置podman拉取和删除镜像给镜像打标签导出和导入镜像创建和删除镜像 1.了解容器及和镜像的关系 对于初学者来说&#xff0c;不太容易理解什么是容器&#xff0c;这里举一个例子。想象一下…