news 2026/11/6 2:48:28

双指针技巧在数组算法中的应用与优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
双指针技巧在数组算法中的应用与优化

1. 合并两个有序数组:从暴力到双指针的优化之路

合并两个有序数组是算法面试中的经典问题,看似简单却暗藏玄机。我们先来看最直观的解法:直接将nums2拼接到nums1末尾,然后调用排序函数。这种方法在C++中可以这样实现:

class Solution { public: void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) { for(int i = 0; i<n; i++){ nums1[m+i] = nums2[i]; } sort(nums1.begin(),nums1.end()); } };

这种解法的时间复杂度是O((m+n)log(m+n)),主要消耗在排序步骤。虽然简单直接,但面试官更希望看到你能利用数组已排序的特性进行优化。

1.1 双指针法的精妙之处

双指针法才是这道题的正解。我们设置三个指针:

  • p1指向nums1的末尾(即第m个元素)
  • p2指向nums2的末尾(即第n个元素)
  • p指向nums1的最终位置(即第m+n个元素)
class Solution { public: void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) { int p1 = m - 1, p2 = n - 1; int p = m + n - 1; while(p1 >= 0 && p2 >= 0){ nums1[p--] = (nums1[p1] > nums2[p2]) ? nums1[p1--] : nums2[p2--]; } while(p2 >= 0){ nums1[p--] = nums2[p2--]; } } };

这种解法的时间复杂度是O(m+n),空间复杂度是O(1),完美利用了nums1末尾的空闲空间。

关键点:从后向前填充可以避免覆盖nums1中尚未处理的元素,这是很多初学者容易忽略的细节。

2. 移除元素:快慢指针的艺术

移除元素问题要求原地修改数组,这提示我们需要使用双指针技巧。快指针遍历数组,慢指针记录有效位置。

2.1 标准双指针解法

class Solution { public: int removeElement(vector<int>& nums, int val) { int slow = 0; for(int fast = 0; fast < nums.size(); fast++){ if(nums[fast] != val){ nums[slow++] = nums[fast]; } } return slow; } };

这种解法的时间复杂度是O(n),空间复杂度是O(1)。但面试官可能会问:如果val元素很少,这种方法会做很多不必要的复制,有没有优化空间?

2.2 优化解法:交换移除

当遇到val时,我们可以将其与数组末尾元素交换,并缩小数组范围:

class Solution { public: int removeElement(vector<int>& nums, int val) { int left = 0, right = nums.size(); while(left < right){ if(nums[left] == val){ nums[left] = nums[right-1]; right--; }else{ left++; } } return left; } };

这种解法在val元素较少时效率更高,因为它减少了元素移动次数。

3. 删除有序数组中的重复项:双指针的变种

这个问题要求每个元素只出现一次,是双指针的经典应用场景。

3.1 基础解法

class Solution { public: int removeDuplicates(vector<int>& nums) { if(nums.empty()) return 0; int slow = 0; for(int fast = 1; fast < nums.size(); fast++){ if(nums[fast] != nums[slow]){ nums[++slow] = nums[fast]; } } return slow + 1; } };

时间复杂度O(n),空间复杂度O(1)。关键在于理解slow指针始终指向最后一个不重复的元素。

3.2 边界情况处理

需要注意空数组和单元素数组的特殊情况:

  • 空数组直接返回0
  • 单元素数组直接返回1

4. 删除有序数组中的重复项 II:允许两次重复

这个问题是前一个问题的升级版,允许元素最多出现两次。

4.1 通用解法

class Solution { public: int removeDuplicates(vector<int>& nums) { if(nums.size() <= 2) return nums.size(); int slow = 2; for(int fast = 2; fast < nums.size(); fast++){ if(nums[fast] != nums[slow-2]){ nums[slow++] = nums[fast]; } } return slow; } };

这个解法的精妙之处在于比较nums[fast]和nums[slow-2],确保最多只保留两个相同元素。

4.2 扩展思考

如果要保留最多k个相同元素,可以将解法抽象为:

int removeDuplicatesK(vector<int>& nums, int k) { if(nums.size() <= k) return nums.size(); int slow = k; for(int fast = k; fast < nums.size(); fast++){ if(nums[fast] != nums[slow-k]){ nums[slow++] = nums[fast]; } } return slow; }

这种抽象思维在面试中很加分,展示了解决一类问题的能力。

5. 多数元素:摩尔投票法的神奇

多数元素问题要求找出出现次数超过⌊n/2⌋的元素,摩尔投票法是最优解。

5.1 摩尔投票法解析

class Solution { public: int majorityElement(vector<int>& nums) { int candidate = nums[0], count = 1; for(int i = 1; i < nums.size(); i++){ if(count == 0){ candidate = nums[i]; count = 1; }else if(candidate == nums[i]){ count++; }else{ count--; } } return candidate; } };

时间复杂度O(n),空间复杂度O(1)。算法核心思想是"多数元素的数量比其他所有元素数量之和还多"。

5.2 算法正确性证明

假设多数元素为x:

  1. 当遇到x时,count加1
  2. 当遇到非x时,count减1
  3. 由于x的数量超过一半,最终count必定大于0

这个算法可以扩展到找出所有出现次数超过n/k的元素,是处理频率统计问题的重要工具。

在实际面试中,除了写出正确代码,还需要:

  1. 分析时间/空间复杂度
  2. 考虑边界条件
  3. 解释算法正确性
  4. 讨论可能的优化空间

掌握这五个问题的解法,你就掌握了数组类算法题的双指针和投票法两大核心技巧。建议在理解的基础上,自己动手实现一遍,并尝试解决类似的变种问题,如:

  • 合并K个有序链表
  • 移除链表中的重复元素
  • 找出数组中出现次数超过n/3的元素等

算法能力的提升在于不断思考和练习,希望这些经典问题的解析能为你的面试准备提供帮助。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/6 2:47:33

footprint-studio:设计与实现 – 云楼(中国)

把旅行与居住足迹变成可交互的 3D 地球&#xff0c;嵌入博客、主页与简历。 技术标签&#xff1a;WebGL MapLibre GL JS Web Component 独立产品 为什么做这个项目 “足迹可视化”并不是一个新需求。旅行博主想在文章末尾放一张“去过的地方”&#xff0c;开发者想在个人主…

作者头像 李华
网站建设 2026/11/6 2:47:02

WPF TreeView 拖拽卡住原因与四阶段修复方案

简介&#xff1a;本资源是一份面向WPF中高级开发者的TreeView拖拽功能实战示例&#xff0c;聚焦解决层次化数据节点的自由重排、移动与复制需求&#xff0c;适用于桌面管理类、配置树编辑、组织架构调整等典型业务场景。压缩包共12个文件&#xff0c;含6个C#逻辑文件&#xff0…

作者头像 李华
网站建设 2026/11/6 2:46:26

Informatica PowerCenter:企业级数据集成中枢解析

简介&#xff1a;本资源是一份面向数据工程师、ETL开发人员及企业级数据治理从业者的Informatica PowerCenter入门与核心功能详解文档&#xff0c;聚焦数据集成架构设计、实时/批量处理模式选型、自助式映射构建及合规审计实践。文档系统梳理PowerCenter在B2B数据交换、主数据管…

作者头像 李华
网站建设 2026/11/6 2:46:26

2026本科毕业论文写作工具全攻略与AI应用趋势

1. 论文写作工具现状与需求分析2026届本科毕业生正面临着前所未有的学术写作挑战。随着高校对学术规范要求的不断提高和查重系统的日益智能化&#xff0c;传统写作方式已难以满足当代大学生的论文需求。根据我对近三年本科毕业论文指导的经验&#xff0c;90%的学生在开题报告阶…

作者头像 李华
网站建设 2026/11/6 2:44:26

Excel天时分文本转小时数:批量转换与验证方法

做数据统计的朋友大概率都遇到过这种表格&#xff1a;系统导出的工时记录里&#xff0c;时间被拆成了“X天X小时X分”三段&#xff0c;或者干脆是“3天5小时20分”这样一整串文本。你想拿它去算总工时、算加班费、做月度汇总&#xff0c;Excel 直接给你一个左对齐的文本&#x…

作者头像 李华
网站建设 2026/11/6 2:44:24

SWMM水文模块底层逻辑与参数校准实战指南

简介&#xff1a;本资源为《SWMM用户参考手册-水文学》中文版PDF&#xff0c;是城市雨水管理领域核心工具SWMM模型&#xff08;EPA官方开发&#xff09;的汉化权威文档第I卷&#xff0c;面向环境工程、市政给排水、城市规划等方向的工程师、科研人员及高校师生&#xff0c;解决…

作者头像 李华