当前位置: 首页 > news >正文

算法题 双指针

 : 三数之和

解题思路 : 排序 + 双指针

要解决这道题,我们可以采用排序 + 双指针的方法:该问题要求找出所有和为 0 且不重复的三元组。核心思路是将“三数之和”转化为固定一个值之后的“两数之和”,利用排序和双指针来高效解决,同时处理重复元素以满足“不重复”的要求。
 
1. 排序:先对数组进行升序排序。排序后,方便我们利用双指针缩小范围,也便于处理重复元素(相同的元素会相邻)。
2. 固定第一个数  a :遍历数组,固定第一个数  nums[i] (记为  a )。为了避免无意义的计算,当  a > 0  时可以直接 break(因为数组已升序,后面的数都更大,三数之和不可能为  0 );同时  a  要满足  a <= 0 (否则三数之和必然大于  0 )。
3. 双指针找另外两个数:在固定  a  之后,剩下的两个数需要满足  b + c = -a 。我们在  a  后面的区间  [i+1, n-1]  中,用左指针  left (初始为  i+1 )和右指针  right (初始为  n-1 )来寻找这两个数:
   - 若  nums[left] + nums[right] > -a ,说明和太大,将  right  左移(减小和);
   - 若  nums[left] + nums[right] < -a ,说明和太小,将  left  右移(增大和);
   - 若  nums[left] + nums[right] == -a ,则找到一个有效三元组  [a, nums[left], nums[right]] 。
4. 去重处理:
   - 找到一个三元组后, left  和  right  要跳过重复的元素(否则会得到重复的三元组);
   - 固定  a  的指针  i ,在遍历完一次后也要跳过重复的元素。

解题代码:

class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> ret;  // 存储最终结果的二维数组sort(nums.begin(), nums.end());  // 步骤1:对数组排序int n = nums.size();for(int i = 0; i < n; ) {  // 步骤2:固定第一个数a(nums[i])if(nums[i] > 0) break;  // a>0时,后续三数之和必大于0,直接退出循环int left = i + 1;  // 左指针,从i的下一个位置开始int right = n - 1;  // 右指针,从数组末尾开始int target = -nums[i];  // 另外两个数的和需要等于 -awhile(left < right) {  // 双指针循环,寻找b和cif(nums[left] + nums[right] > target) {right--;  // 和太大,右指针左移} else if(nums[left] + nums[right] < target) {left++;  // 和太小,左指针右移} else {// 找到有效三元组,存入结果ret.push_back({nums[i], nums[left], nums[right]});left++;right--;// 跳过left的重复元素while(left < right && nums[left] == nums[left - 1]) left++;// 跳过right的重复元素while(left < right && nums[right] == nums[right + 1]) right--;}}i++;// 跳过i的重复元素while(i < n && nums[i] == nums[i - 1]) i++;}return ret;}
};
  • 排序操作: sort(nums.begin(), nums.end())  对数组升序排序,为后续双指针和去重奠定基础。
  • 遍历固定  a : for  循环中  i  是固定  a  的指针,循环内先判断  nums[i] > 0  直接 break,避免无效计算。
  • 双指针逻辑: while(left < right)  循环中,通过调整  left  和  right  的位置来寻找和为  target (即  -a )的两个数。
  • 去重细节:
  •     找到三元组后, left++  和  right--  后,通过  while  循环跳过与上一个元素相同的  left  和        right , while 循环中为了防止越界必须先判断 left<right ;
  •     i  遍历后,通过  while  循环跳过与上一个元素相同的  i ,避免重复的  a  导致重复三元组。
  •     最后 i++ 后可能会存在越界的可能 , 所以在 while 循环中需要先判断 i<n

注意事项:

1. 去重细节

  • 固定数  a  的去重:当遍历到  nums[i]  时,如果它和前一个元素  nums[i-1]  相同,需要跳过,否则会生成重复的三元组。例如数组  [0,0,0,0] ,若不跳过重复的  i ,会多次处理相同的  a ,导致结果中出现多个  [0,0,0] 。
  • 双指针的去重:找到一组满足条件的  (left, right)  后, left  需要跳过后续所有相同的元素, right  也需要跳过前面所有相同的元素。比如数组  [-2,0,0,2,2] ,当找到  -2,0,2  后, left  要从第二个  0  跳到  2 , right  要从第二个  2  跳到第一个  2  的前一个位置,避免重复计算  [-2,0,2] 。

2. 边界条件

  • a > 0  的提前终止:因为数组已经排序,当  nums[i] > 0  时,后面的数都大于等于  nums[i] ,三数之和必然大于  0 ,可以直接终止循环,减少无效计算。
  • 双指针的范围控制:要保证  left < right ,否则会出现指针越界或重复计算的情况。

3. 数组长度的限制

  • 题目中说明  3 <= nums.length <= 3000 ,需要确保代码在处理这个长度范围内的数组时不会出现性能问题,而 排序 + 双指针 的方法时间复杂度为O(n^2),在这个数据规模下是可行的。

4. 结果的存储

  • 需要用一个二维数组来存储所有符合条件的三元组,每次找到符合条件的三元组时,要将其正确地添加到结果数组中,注意元素的顺序(按照  a, b, c  的顺序,即  nums[i], nums[left], nums[right] )。

这种方法的时间复杂度为 O(n^2)(排序为 O(n\log n),外层遍历 O(n),内层双指针 O(n),整体由 O(n^2) 主导),空间复杂度为 O(\log n)(主要为排序的空间开销),能够高效解决该问题

http://www.dtcms.com/a/618815.html

相关文章:

  • 问答网站怎么做营销建设单位到江川区住房和城乡建设局网站
  • 大数据实用指南:etl + ambari
  • ONAP网络自动化平台介绍与架构
  • 网站开发确认表购物网站后台模板下载
  • 网站模板安全管理系统外贸网站定做
  • 商务礼品网站模板买卖友情链接
  • 解码线程编程
  • 杰恩设计网站是谁做的百度一下百度一下百度一下
  • 哈希表和冲突处理
  • seo网站建设是什么wordpress首页加广告位
  • 网站开发所需硬件山东建设银行官方网站
  • Adversarial AtA学习(第二十三周周报)
  • 阿里云企业网站备案农村建设自己的网站首页
  • Unity UI框架笔记
  • 15个html5手机网站模板深圳万户网络技术有限公司
  • 网站开发是编程吗网站logoico怎么做
  • 力扣-二叉树的前序遍历
  • 安全联盟可信任网站认证 网站商城系统app开发
  • 做网站的 深圳没有网站做APP
  • 淘宝软件营销网站建设网站建设公司业务培训
  • 【第二十二周】自然语言处理的学习笔记06
  • 重庆ssc做号网站整站外包优化公司
  • Java数据结构-List-栈-队列-二叉树-堆
  • 如何在godaddy空间做手机网站资源wordpress
  • 【科技素养】蓝桥杯STEMA 科技素养组模拟练习试卷 5
  • 建立网站需要注册公司吗小制作废品利用
  • thinkphp做直播网站wordpress极验验证注册
  • 世赛网站开发拉新推广
  • SLAM中的非线性优-3D图优化之李群李代数在Opencv-PNP中的应用(四)
  • 做网站什么分类流量多动漫设计与制作学校