力扣校招算法通关:双指针技巧全场景拆解 —— 从数组操作到环检测的高效解题范式

力扣校招算法通关:双指针技巧全场景拆解 —— 从数组操作到环检测的高效解题范式

文章目录

前言

在力扣校招算法题中,双指针技巧是一类高频且实用的解题方法。它并非真正的 “指针”,而是通过两个数组下标(或迭代器)的协同移动,在数组划分、区间求解、环检测等场景中实现高效遍历与逻辑处理,往往能将时间复杂度从暴力法的 O(n平方)优化至O(n),是校招笔试和面试中突破数组类难题的关键武器。

本专栏将围绕力扣校招高频的双指针题型展开,从 “移动零”“复写零” 的数组操作,到 “快乐数” 的环检测、“盛最多水的容器” 的区间优化,再到 “三数之和” 的多指针协同,逐一拆解双指针的核心逻辑、边界处理与去重技巧,帮助你建立 “看题辨双指针,提笔知如何移” 的解题思维,从容应对校招算法考察中的数组类挑战。

双指针

常用于:数组划分和数组分块

注意:这里的指针不是真的指针,是数组的下标

例题讲解

移动零 力扣

283. 移动零

cur:从左往右遍历数组

dest:已处理区间内,非零元素的最后一个位置
在这里插入图片描述
代码展示:classSolution{public:voidmoveZeroes(vector<int>& nums){int dest =-1;int cur =0;for(;cur<nums.size();cur++){if(nums[cur]!=0){swap(nums[dest+1],nums[cur]); dest++;}else{;}}}};

复写零 力扣

1089. 复写零

注意:这题要求不要在超过该数组长度的位置写入元素

步骤:

一:先找到最后一个被复写的数

找法:1.先判断cur位置的值(cur放到下标0位置,dest放到下标-1位置)

5.如果dest超过最后那个数的位置

二:从后向前完成复写操作
引申:vector的size()-1就是最后一个位置的下标 区分元素和下标 区分==和= 注意:size()在用来表示下标的时候,建议赋值给int类型的之后再用 不然 eg:dest<a.size()-1的时候,dest会整形提升,如果是-1就惨了 
代码展示:classSolution{public:voidduplicateZeros(vector<int>& arr){int cur =0;int dest =-1;for(;dest<(int)arr.size()-1;cur++){if(arr[cur]==0) dest++; dest++;} cur--;if(dest == arr.size()){ arr[arr.size()-1]=0; dest-=2; cur--;}for(;cur>=0;cur--){ arr[dest]= arr[cur];if(arr[cur]==0) arr[--dest]=0; dest--;}}};

快乐数 力扣

202. 快乐数

这么说的话,那就只有可能为1或者无限循环(和无限不循环区分)--所以想到环 环的话用快慢双指针去解决 注意:快慢指针的起点都是n 快慢指针一定会在环入口相遇 
引申:一定要动手模拟一下示例
代码展示:classSolution{public:intalgorithm(int p){int sum =0;int q =0;while(p>=10){ q = p%10; p/=10; sum+=q*q;} sum+=p*p;return sum;}boolisHappy(int n){int slow = n;int fast = n; slow =algorithm(n); fast =algorithm(slow);while(slow!=fast){ slow =algorithm(slow); fast =algorithm(fast); fast =algorithm(fast);}if(slow ==1)returntrue;elsereturnfalse;}};

盛最多水的容器 力扣

11. 盛最多水的容器

做法:left放在最左边,right放在最右边

比较完之后,看left和right哪个对应的值小些,就把哪个向另外一边靠近
代码展示:classSolution{public:intmaxArea(vector<int>& height){int cur =0;int dest = height.size()-1;int max1 =0;while(cur!=dest){ max1 =max(max1,(dest-cur)*min(height[dest],height[cur]));if(height[cur]<height[dest]) cur++;else dest--;}return max1;}};

有效三角形的个数 力扣

611. 有效三角形的个数

相关数学知识: 三角形最小的那两边之和>最大那一边就可以构成三角形了
方法:先给数组排序,然后先固定最大的数,在最大的数的左边用双指针算法去找符合的数;然后再缩小最大的数…

注意:如果nums[left]+nums[right]>nums[c],那right-left就是第二大数下标为rgiht时的总个数,然后right--)

注意区分c和nums[c]!!!
代码展示: classSolution{public:inttriangleNumber(vector<int>& nums){sort(nums.begin(),nums.end());int c = nums.size()-1;int ret =0;while(c>=2){int left =0;int right = c-1;while(left!=right){if((nums[left]+nums[right])>nums[c])//记得加括号{ ret+=right-left; right--;}else left++;} c--;}return ret;}};

查找总价格为目标值的两个商品 力扣

查找总价格为目标值的两个商品

这个题有单调性,用双指针正好(或者二分算法)–能用双指针肯定优先用双指针

注意:此题没说找不到怎么办,就不用管那种情况,但是!力扣要求所有路径都要有返回值,在最后加个return …就行了,但是要是能转化为vector<int>类型的,比如nullptr就不行
引申:eg: return {1,1};可以被隐式转成vector<int>类型的(函数返回值是vector<int>的情况下) 
代码展示:classSolution{public: vector<int>twoSum(vector<int>& price,int target){ vector<int>ret;int left =0;int right = price.size()-1;while(left!=right){if(price[left]+price[right]>target) right--;elseif(price[left]+price[right]<target) left++;else{ ret.push_back(price[left]); ret.push_back(price[right]);break;}}return ret;}};

三数之和 力扣

三数之和

这种和怎么样怎么样的一般都排序之后用双指针

这个题跟上面的有效三角形的个数有点像
细节问题:

1.去重

left和right以及固定的那个数都要跳过重复元素(哪个跟哪个比较==才去要注意)–于此同时要避免越界,比如:left一直要<right

补充:当然也可以找出所有结果之后,用unordered_set去重——可是,去面试的时候这两种方法都可能会问到

2.不漏

找到一种结果之后,不能直接break出去,要eg:left++;right--继续寻找
引申:迭代器和下标怎么确立关系:(下标为p)–迭代器连续的那种才行(eg:vector算,list不算)

eg:auto a = ret.begin()+p

eg:int a = 1,double b = 0;是不行的
引申:题目给的target不要直接拿来运算,不然后续想要原来的就难了 eg:vector<vector<int>>的取名叫vv很好 溢出问题很容易读题时考虑到,后面又忘了--比如应该写long long int 又写成了int 
代码展示:classSolution{public: vector<vector<int>>threeSum(vector<int>& nums){ vector<vector<int>> ret;sort(nums.begin(),nums.end());int i =0,j =0;for(int k = nums.size()-1;k>=2;k--){if(nums[k]<0)break; i =0;j = k-1;while(i<j){if(nums[i]+nums[j]+nums[k]>0) j--;elseif(nums[i]+nums[j]+nums[k]<0) i++;else{ ret.push_back({nums[i],nums[j],nums[k]}); i++;j--;//去重while(nums[i]== nums[i-1]&&i<j) i++;while(nums[j]== nums[j+1]&&i<j) j--;}}while(nums[k]== nums[k-1]&&k>=2) k--;}return ret;}};

Read more

Hadoop 核心组件详解:HDFS、YARN、MapReduce 如何各司其职?

Hadoop 核心组件详解:HDFS、YARN、MapReduce 如何各司其职?

Hadoop 核心组件详解:HDFS、YARN、MapReduce 如何各司其职? * 一、Hadoop 核心组件全景图 * 二、HDFS:分布式文件系统 * 1. 架构角色 * 2. 读写流程(流程图) * HDFS 写数据流程 * HDFS 读数据流程 * 三、YARN:资源调度与管理系统 * 1. 架构角色 * 2. YARN 的任务提交流程 * 四、MapReduce:分布式计算框架 * 1. 核心思想 * 2. 经典 WordCount 代码示例 * 3. MapReduce 完整执行流程 * 五、总结:三驾马车的协同 🌺The Begin🌺点点关注,收藏不迷路🌺 大数据时代,面对海量数据的存储与计算,

By Ne0inhk
Flutter 组件 easter 适配鸿蒙 HarmonyOS 实战:天文学节气算法,构建全球化复活节周期与民俗历法治理架构

Flutter 组件 easter 适配鸿蒙 HarmonyOS 实战:天文学节气算法,构建全球化复活节周期与民俗历法治理架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 easter 适配鸿蒙 HarmonyOS 实战:天文学节气算法,构建全球化复活节周期与民俗历法治理架构 前言 在鸿蒙(OpenHarmony)生态迈向全球化部署、涉及跨区域文化适配(I18n)及复杂变动日期计算的背景下,如何精确推演具备“阴阳历混合特性”的全球性节日(如复活节),已成为决定跨国类应用“运营确定性”的核心技术难点。在鸿蒙设备这类强调 AOT 极致性能与低功耗常驻服务(AOD)的环境下,如果应用依然依赖手动配置的“节日死表”,由于由于复活节日期在全球范围内的复杂游移性,极易由于由于配置滞后导致海外营销活动的时序错乱。 我们需要一种能够实现高精度天文学推演、支持百年尺度计算且具备纯 Dart 离线运作能力的历法预判方案。 easter 为 Flutter 开发者引入了基于高斯算法(Gauss's algorithm)或曼氏算法(Meeus&

By Ne0inhk
单链表的实现(数据结构)

单链表的实现(数据结构)

一. 单链表的实现 我们在上一篇中简单的认识了链表的组成和结构,并打印出链表,那么今天就来具体实现一下单链表对于数据增加、删减、插入等。 接下来就是我们在链表中对于数据的增、删、插的实现,对于我们的链表来说在任何地方增加数据都需要来申请一个新的结点,首先呢,SLDatatype是我们更改int类型的名称之后得来的,SL是结构体的名称,我们先申请一个结构体大小的新结点node,然后再将新结点中的x的值赋给data,再让新结点的next指向NULL,申请新结点的函数写好之后我们就来写关于数据的增、删、插等,所以我们直接先来完成申请新结点的代码: SLDatatype* SLBuyNode(SLDatatype x) { SL* node = (SL*)malloc(sizeof(SL)); if (node == NULL) { perror("malloc fail!"); exit(1); } node->data = x; node->next = NULL; return

By Ne0inhk
面试题 02.04. 分割链表 - 题解与详细分析

面试题 02.04. 分割链表 - 题解与详细分析

题目描述 给你一个链表的头节点 head 和一个特定值 x,请你对链表进行分隔,使得所有小于 x 的节点都出现在大于或等于 x 的节点之前。 你不需要保留每个分区中各节点的初始相对位置。 示例 示例 1: 输入: head = [1,4,3,2,5,2], x = 3 输出: [1,2,2,4,3,5] 示例 2: 输入: head = [2,1], x = 2 输出: [1,2] 提示: * 链表中节点的数目在范围 [0, 200] 内 * -100 <

By Ne0inhk