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

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

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

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

   三数之和

  题目来源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.mfbz.cn/a/241501.html

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

相关文章

Linux——MySQL数据库的使用

访问MySQL数据库 MySOL数据库系统也是一个典型的C/S&#xff08;客户端/服务器&#xff09;架构的应用&#xff0c;要访问MySOL数据库 需要使用专门的客户端软件&#xff0c;在Linux系统中&#xff0c;最简单、易用的MySQL.客户端软件是其自带的mysql 命令工具。 登录到MySQL服…

Vue3-13- 【v-for】循环一个对象

说明 v-for 这个东西就很神奇&#xff0c;可以遍历一个对象&#xff0c; 当然&#xff0c;它遍历对象是通过 对象的属性名&#xff0c;遍历对象的属性值。语法格式如下 &#xff1a; v-for"(value,key,index) in objName" value : 属性的值 key &#xff1a;属性的k…

商品规格的实现

在商城项目中购买商品或者添加购物车的时候都会让我们去选择商品的规格,颜色、尺码、风格等,这里把刚做完的此功能代码记录下,方便以后查阅: <template><view><u-navbar title="测试"></u-navbar><view class="content"&g…

多篇整合版:最全电商erp系统接口测试实战

之前我们讲了电商ERP系统接口简介以及如何使用post方式获取接口请求 &#xff0c;今天我们来讲解如何用JMeter实现接口功能、性能测试。 内容&#xff1a; JMeter实现接口功能测试 JMeter实现接口的性能测试 JMeter实现接口功能测试 企业性能测试编写脚本过程&#xff1a;接口…

java学生选课系统 数据库版

首先让我们创建一个数据库 让我们向表中插入数据然后查询它

WSL 配置 Docker 内存和 CPU 资源限制

我用的电脑一共有40G内存&#xff0c;最近发现电脑重启后&#xff0c;VmmemWSL 进程很快就会占用一多半的内存&#xff08;20G&#xff09;&#xff0c;电脑中有多个停止运行的容器&#xff0c;正常启动状态的只有一个 MySQL 服务&#xff0c;通过 docker stats 查看占用内存也…

【详解优先级队列(堆)】

目录 堆的概念 堆的性质 堆的存储方式 堆的创建 堆的向下调整 向下过程(以小堆为例) 向下过程(以大堆为例) 建堆的时间复杂度O(n) 堆的插入与删除 堆的插入 向上调整建堆的时间复杂度O(nlogn) 堆的删除 常见习题 常用接口介绍 PriorityQueue的特性 Pri…

实战1-python爬取安全客新闻

一般步骤&#xff1a;确定网站--搭建关系--发送请求--接受响应--筛选数据--保存本地 1.拿到网站首先要查看我们要爬取的目录是否被允许 一般网站都会议/robots.txt目录&#xff0c;告诉你哪些地址可爬&#xff0c;哪些不可爬&#xff0c;以安全客为例子 2. 首先测试在不登录的…

使用MIB builder自定义物联网网关的MIB结构

文章目录 物联网网关初识&#xff08;了解即可&#xff09;IoT的通用MIB库结构MIB Builder开发流程指导问题总结子叶没所属分组值范围不为0 物联网网关初识&#xff08;了解即可&#xff09; 网关又称网间连接器、协议转换器。简单说&#xff0c;物联网网关是一台智能计算机&a…

【Java】网络编程-UDP回响服务器客户端简单代码编写

这一篇文章我们将讲述网络编程中UDP服务器客户端的编程代码 1、前置知识 UDP协议全称是用户数据报协议&#xff0c;在网络中它与TCP协议一样用于处理数据包&#xff0c;是一种无连接的协议。 UDP的特点有&#xff1a;无连接、尽最大努力交付、面向报文、没有拥塞控制 本文讲…

《算法通关村——回溯模板如何解决回溯问题》

《算法通关村——回溯模板如何解决回溯问题》 93. 复原 IP 地址 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"0.1.2.201" 和 "192.1…

IDEA2023找不到add framework support怎么解决

问题: 我的idea版本是2023.01&#xff0c;新版idea右键项目没有Add Framework Support&#xff0c;help里面也找不到相关的。 从project structue的facets里面添加就行了&#xff0c;都是一样的。 1.依旧是新建一个项目 2.file-->project structure--->facets 左上角加…

JavaEE 09 锁策略

1.锁策略 1.1 乐观锁与悲观锁 其实前三个锁是同一种锁,只是站在不同的角度上去进行描述,此处的乐观与悲观其实是指在预测的角度上看会发生锁竞争的概率大小,概率大的则是悲观锁,概率小的则是乐观锁 乐观锁在加锁的时候就会做较少的事情,加锁的速度较快,但是消耗的cpu资源等也会…

crmeb v5自动生成代码报错(adminInfo方法或404路由不存在的问题)

404 现象 调试器中出现了404 , 那肯定是路由出了问题,也就是说,crmeb 为我们生成的路由没有对应的加载上,先来看一下, 自动代码为我们生成的路由是什么样子的 所以有一种最简单的解决办法,就是 把 新生成的路由文件从子目录中挪出一级来,就可以解决404的问题了 下面来说…

python学习:浅拷贝与深拷贝详解

copy 一、 & is二、浅拷贝 & 深拷贝(一)、浅拷贝(二)、深拷贝 三、问题 一、’ ’ & ‘is’ ’ 和is是python对象比较常用的两种方式,简单来说,‘ ‘操作符比较对象之间的值是否相等,如 a b 而’is’操作符比较的是对象的身份标识是否相等,即它们是否是同一个…

「玩转 TableAgent 数据智能分析」实战数据分析演练

文章目录 前言TableAgent 功能亮点人人都是数据分析师融合创新应用的新成果 TableAgent 使用介绍登陆功能介绍申请认证 实战数据集分析一导入 CSV 文件数据发起提问TableAgent 应答结果贴切的服务推荐问题提问 实战数据集分析二分析结果分析哪个城市的未来人口最多 总结 TableA…

linux高级管理——访问MYSQL数据库

一、认识数据库系统&#xff1a; MySQL数据库系统也是一个典型的C/S(客户端/服务器&#xff09;架构的应用&#xff0c;要访问MySQL数据库需要使用专门的客户端软件。在Linux系统中&#xff0c;最简单、易用的MySQL客户端软件是其自带的mysql命令工具。 1&#xff0e;登录到My…

光伏开发设计施工一体化系统都有哪些功能?

随着全球对可再生能源的需求不断增加&#xff0c;光伏行业得到了快速发展。同时也面临着一些挑战&#xff0c;例如初始投资成本高、需要大量土地和水资源等。鹧鸪云光伏与储能软件利用技术创新&#xff0c;促进光伏行业数字化升级。 一、智能测算 1.投融资表&#xff1a;采用…

【FPGA/verilog -入门学习6】verilog频率计数器

需求 在使能信号控制下&#xff0c;计算输入脉冲的每两个上升沿之间的时钟周期数并输出&#xff0c;即输出脉冲频率的计数值 输入信号 周期性脉冲信号&#xff1a;需要做检测的脉冲频率信号 使能信号&#xff1a;高电平进行频率计数&#xff0c;低电平清零计数器 输出信号 计数…

bootstrap:下拉菜单

<!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>下拉菜单DEMO</title> <link rel"stylesheet" type"text/css" href"/cdn.bootcss.com/bootstrap/3.3.2/css/bootstrap.min.css"…
最新文章