每日一题——三数之和(双指针)

这篇具有很好参考价值的文章主要介绍了每日一题——三数之和(双指针)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

每日一题

三数之和

题目链接

每日一题——三数之和(双指针)

思路

解析函数原型
  • 首先我们来看一下题目给的函数原型:

    int** threeSum(int* nums, int numsSize, int* returnSize, int**returnColumnSizes)
    
    • 题目要求我们返回一个二维数组,数组的行数代表着存在多少个满足条件的三元组,而在本题中,列数规定为3,即每行存储3个元素
    • 在螺旋矩阵中我们已经做过分析,nums就是题目给的整数数组,numsSize就是这个数组的大小,returnSize就是我们返回的二维数组的行数,returnColumnSizes是一个一维数组,它储存的就是我们返回的二维数组的每一行的列数。
整体框架
  • 这一题其实就是昨天两数之和拓展部分的进阶版,在《两数之和》中我们提到,如果题目要求我们返回的是满足条件的三个元素的数值,那我们就可以采用双指针的办法来解决问题

  • 使用双指针的前提条件,就是要确保数组是有序的,因为只有这样,才能保证left右移时,sum变大,right左移时sum变小,因此我们第一步就是要对数组进行排序

  • 那么具体的,我们怎么使用双指针这一方法呢?

    • 首先利用一层循环,来遍历整个数组

      for(int i = 0; i < numsSize; i++)
      {
          ………………;
      }
      
    • 然后我们用left指向i的后一个元素,right指向数组nums的最后一个元素,这里我们令nums[i] = a, nums[left] = b, nums[right] = c, sum = a + b + c

    • 接下来,就和《两数之和》里的方法类似了,如果sum > 0,那么right–,如果sum < 0,那么lerft++,如果sum == 0,那么就将a,b,c这三个数存入结果数组中

      for(i = 0; i < numsSize; i++)
      {
          int left = i + 1;
          int right = numsSize - 1;
          while(left < right)
          {
              int sum = nums[i] + nums[left] + nums[right];
              if(sum > 0)
                  right--;
              else if(sum < 0)
                  left++;
              else
              {
      			//存入数据
              }
          }
      }
      
    • 过程如图:

      每日一题——三数之和(双指针)

去重
  • 可以看到,这一个例子的结果集为{{-1,-1,2},{-1,0,1},{-1,0,1}},但是题目要求,答案中不能包含重复的三元组,因此我们还要考虑去重的问题

  • a(nums[i])的去重:

    • 由于数组有序,且a是遍历数组的值,因此a便不允许重复出现

    • 那么我们是要判断nums[i] == nums[i + 1]还是判断nums[i] == nums[i - 1]呢?

    • 假设给定的数组为{-1,-1,2},如果我们用if(nums[i] == nums[i + 1])进行判断 ,那么第一个-1就会被跳过,这个三元组就不会被计入到结果集中,显然这是不合理的

    • 而用if(nums[i] == nums[i - 1)进行判断就不会出现这种情况

    • 为什么会出现这种情况?我们要清楚题目要求的是不能出现重复的三元组,而不是三元组中不能出现重复的元素,如果用第ifif(nums[i] == nums[i + 1])判断,那么就会将三元组中出现重复元素这一情况给排除,不合题意

      if(i > 0 && nums[i] == nums[i - 1])		//加上i > 0是为了防止数组越界访问
          continue;
      
  • b(nums[left]),c(nums[right])的去重

    • 当我们执行left++,right- -操作的时候,如果nums[left] == nums[++left],或nums[right] == nums[- -right],那么显然也会出现重复的情况,因此当出现相等时,我们就要继续++left,或- -right文章来源地址https://www.toymoban.com/news/detail-464917.html

      while(left < right && nums[right] == nums[--right]);
      while(left < right && nums[left] == nums[++left]);
      
      //也可以写为
      /*
      while(left < right && nums[right] == nums[right - 1])
      	right--;
      while(left < right && nums[left] == nums[left + 1])
      	left++;
      */
      

实现代码

/**
 * 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().
 */
 //将数组从小到大排序
void Sort(int *nums, int numsSize)
{
    for(int i = 0; i < numsSize - 1; i++)
    {
        for(int j = i + 1; j < numsSize; j++)
        {
            if(nums[i] > nums[j])
            {
                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
            }
        }
    }
}
int** threeSum(int* nums, int numsSize, int* returnSize, int**returnColumnSizes){
    int base = 100;     //假设有100组数
    
    //申请内存
    int **arr = (int **)malloc(sizeof(int *) * base);	
    *returnColumnSizes = (int *)malloc(sizeof(int) * base);	
    
    //三元组的个数初始化为0
    *returnSize = 0;
    
    Sort(nums,numsSize);    //将数组从小到大排序
    
    //如果最小的数都大于0,那么直接返回空数组
    if(nums[0] > 0)
        return NULL;
    
    //开始寻找符合条件的三元组
    int i = 0;
    for(i = 0; i < numsSize; i++)
    {
        //a的去重
        if(i > 0 && nums[i] == nums[i - 1])
            continue;
        
        int left = i + 1;
        int right = numsSize - 1;
        
        //双指针查找
        while(left < right)
        {
            int sum = nums[i] + nums[left] + nums[right];
            if(sum > 0)
                right--;
            else if(sum < 0)
                left++;
            //如果找到符合条件的三个数
            else
            {
                (*returnColumnSizes)[(*returnSize)] = 3;	//将存储第(*returnSize)组三元组的数组的行数确定为3
                //申请存储第(*returnSize)组三元组的数组的内存
                arr[(*returnSize)] = (int *)malloc(sizeof(int) * 3);	
                
                //将数据存入数组
                arr[(*returnSize)][0] = nums[i];
                arr[(*returnSize)][1] = nums[left];
                arr[(*returnSize)][2] = nums[right];
                
                //三元组个数加一
                (*returnSize)++;
                
                //实现b,c去重
                while(left < right && nums[right] == nums[--right]);
                while(left < right && nums[left] == nums[++left]);
                //也可以写成这样
                /*
                while(left < right && nums[right] == nums[right - 1])
                    right--;
                while(left < right && nums[left] == nums[left + 1])
                    left++;
                right--;
                left++;
                */
            }
            
            //如果三元组个数等于初始值base,那么就要进行扩容
            if((*returnSize) == base)
            {
                base *= 2; 
                arr = (int **)realloc(arr,sizeof(int *) * base);
                *returnColumnSizes = (int *)realloc(*returnColumnSizes, sizeof(int) * base);
            }
        }
    }
    
    //返回最终的结果集
    return arr;
}

到了这里,关于每日一题——三数之和(双指针)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 2023/07/11_leetcode每日一题_16. 最接近的三数之和

    给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。 返回这三个数的和。 假定每组输入只存在恰好一个解。 和三数之和那道题一样,排序加双指针

    2024年02月15日
    浏览(62)
  • (双指针 ) 18. 四数之和 ——【Leetcode每日一题】

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

    2024年02月07日
    浏览(58)
  • 【每日一题Day266】LC18四数之和 | 排序+双指针

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

    2024年02月16日
    浏览(39)
  • 【算法】排序+双指针——leetcode三数之和、四数之和

    三数之和 (1)排序+双指针   算法思路: 和之前的两数之和类似,我们对暴力枚举进行了一些优化,利用了 排序+双指针 的思路:   我们先排序,然后固定⼀个数 a ,接着我们就可以在这个数后面的区间内,使用之前两数之和使用的算法,快速找到两个数之和和固定的

    2024年02月13日
    浏览(53)
  • 【算法专题突破】双指针 - 三数之和(7)

    目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后: 题目链接:15. 三数之和 - 力扣(Leetcode)  题目就是要找出和为0的不重复的三元组, 注意三元组的每个元素是得不同的位置,那不重复又是什么意思呢? 我们可以看第一个示例, 他找出了三个三元组,但是他最后只返回

    2024年02月09日
    浏览(40)
  • 【算法专题--双指针算法】leecode-15.三数之和(medium)、leecode-18. 四数之和(medium)

    🍁你好,我是 RO-BERRY 📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 双指针 常见的双指针有两种形式,一种是对撞指针,⼀种是左右指针。 对撞指针:一般用于顺序结构中

    2024年04月09日
    浏览(49)
  • [双指针] (三) LeetCode LCR 179. 查找总价格为目标值的两个商品 和 15. 三数之和

    [双指针] (三) LeetCode LCR 179. 查找总价格为目标值的两个商品 和 15. 三数之和 查找总价格为目标值的两个商品 LCR 179. 查找总价格为目标值的两个商品 题目分析 (1) 数组内数字是升序 (2) 目标值为target (3) 找两数之和为target 解题思路 找两个数字的和与目标值相等,我们可以想到

    2024年02月05日
    浏览(50)
  • 【力扣每日一题01】两数之和

    开了一个新专栏,用来记录自己每天刷题,并且也是为了养成每日学习这个习惯,期待坚持一年后的自己! 给定一个整数数组  nums  和一个整数目标值  target ,请你在该数组中找出  和为目标值  target   的那  两个  整数,并返回它们的数组下标。 你可以假设每种输入只

    2024年02月10日
    浏览(49)
  • 2023-07-15 LeetCode每日一题(四数之和)

    点击跳转到题目位置 给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且 不重复 的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复): 0 = a, b, c, d n a、b、c 和 d 互不相同 nums[a] + nums[b]

    2024年02月16日
    浏览(47)
  • 【力扣每日一题】2023.7.15 四数之和

    这题和本月出过的每日一题:两数之和,三数之和类似。 不夸张的说只要把三数之和的代码拿来再套层for循环改改就可以了。 不过我这里还是简单捋一捋思路,题目给一个数组,要求返回所有长度为4,总和为 target 的子数组(不用连续)。 比较容易想到的是暴力解法,直接

    2024年02月16日
    浏览(79)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包