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

双指针算法(一)

目录

🔹 移动零(283)

题目要求

核心思路

代码实现

探索思考

🔹 复写零(1089)

题目要求

核心思路

代码实现

探索思考

🔹 快乐数(202)

题目要求

核心思路

代码实现

探索思考

💡 刷题总结


最近刷了三道经典的算法题,分别是「移动零」「复写零」和「快乐数」,每一道都有巧妙的解题思路。我想把这些思路和对应的代码实现记录下来,也算是一次探索性学习的总结。


🔹 移动零(283)

题目要求

把数组里所有的0移动到末尾,同时保持非零元素的相对顺序,必须原地操作

核心思路

这是一个典型的双指针问题:

  • left指针:指向当前可以放置非零元素的位置(初始为-1
  • right指针:遍历整个数组
  • right遇到非零元素时,就和left+1位置的元素交换,这样保证了非零元素的顺序,也把0挤到了后面

代码实现

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

探索思考

这道题的关键是理解 “原地操作” 的含义。如果允许使用额外数组,直接把非零元素存进去再补零就可以了,但双指针的方法让空间复杂度降到了O(1),是最优解。


🔹 复写零(1089)

题目要求

遍历数组,遇到0就把它复写一遍,后面的元素右移,且不能超过数组长度

核心思路

这道题的难点在于如果直接从前往后复写,会覆盖掉还没处理的元素。所以我们用两次遍历的思路:

  1. 第一次遍历:用curdest两个指针,计算出最终每个元素的目标位置,找到最后一个需要保留的元素。
  2. 第二次遍历:从后往前复写,这样就不会覆盖未处理的元素。如果最后一个元素是0且刚好超出数组长度,需要单独处理。

代码实现

class Solution { public: void duplicateZeros(vector<int>& arr) { int cur = 0, dest = -1; int n = arr.size(); // 第一次遍历:找到最终的位置 while (cur < n) { if (arr[cur]) dest++; else dest += 2; if (dest >= n - 1) break; cur++; } // 处理边界情况:最后一个0复写后超出数组 if (dest == n) { arr[n - 1] = 0; cur--; dest -= 2; } // 第二次遍历:从后往前复写 while (cur >= 0) { if (arr[cur]) { arr[dest--] = arr[cur--]; } else { arr[dest--] = 0; arr[dest--] = 0; cur--; } } } };

探索思考

从后往前的逆向思维是这道题的精髓。如果正向操作,每次遇到0都要移动后面的元素,时间复杂度会达到O(n²),而两次遍历的方法把时间复杂度降到了O(n),非常高效。


🔹 快乐数(202)

题目要求

判断一个数是不是快乐数:反复计算各位数字的平方和,最终如果能得到1就是快乐数,否则会进入无限循环。

核心思路

这道题的关键是如何判断 “无限循环”。我们可以用 ** 快慢指针(Floyd 判圈算法)** 来检测循环:

  • slow指针:每次计算一次平方和
  • fast指针:每次计算两次平方和
  • 如果存在循环,fast最终会追上slow;如果是快乐数,slow会先到达1

代码实现

class Solution { public: int bitsum(int n) { int sum = 0; while (n) { sum += pow(n % 10, 2); n = n / 10; } return sum; } bool isHappy(int n) { int slow = n, fast = bitsum(n); while (slow != fast) { slow = bitsum(slow); fast = bitsum(bitsum(fast)); } return slow == 1; } };

探索思考

这道题也可以用哈希表来记录已经出现过的数字,但快慢指针的方法不需要额外空间,空间复杂度是O(1)。而且判圈算法在很多链表问题中也会用到,是一个非常通用的技巧。


💡 刷题总结

这三道题虽然看起来不同,但都用到了双指针的核心思想:

  • 移动零:同向双指针,一个负责找非零元素,一个负责放置
  • 复写零:两次遍历,正向找位置,逆向写元素
  • 快乐数:快慢指针,检测循环

探索性学习的乐趣就在于,你会发现很多看似无关的问题,背后都有相通的解题思路。多总结、多思考,才能真正把算法内化成自己的能力。

http://www.jsqmd.com/news/747247/

相关文章:

  • WeDLM-7B-Base开源模型:MIT协议,支持商用、二次训练、私有化分发
  • 3步解决Windows内存卡顿:Mem Reduct实时监控与优化指南
  • 程序员必备:用腾讯云/阿里云S3对象存储给Joplin笔记做个‘云备份’(附详细AK/SK配置避坑点)
  • LinkSwift:一键获取网盘直链的智能下载助手
  • 第一章-01-初识对象
  • 利用 Taotoken 模型广场为新产品选择性价比最高的文本生成模型
  • 从素材到出图:Stable Diffusion LoRA训练全流程实操,用XYZ图表自动找出最佳模型
  • Java 25结构化并发生产踩坑图谱(含ThreadPerTaskExecutor泄漏、Scope生命周期越界等8类致命陷阱)
  • LUT(Look-Up Table,查找表)的定义与核心概念
  • notesGPT自动总结功能:如何让AI从语音中提取关键信息
  • 避坑指南:ABB机器人Modbus TCP通讯中浮点数读写与字节序的那些事儿(以西门子1500为例)
  • ISO 14229-5标准解读:手把手配置DoIP诊断中的P2/P6/P4Server超时参数(含Wireshark抓包分析)
  • 2026届学术党必备的AI辅助写作工具实测分析
  • 3步轻松搞定:京东商品监控自动下单工具使用全攻略
  • unity中UI管理器的详解及其优化
  • JDK17+Project Leyden落地边缘场景:为什么92%的Java边缘项目仍用冗余JRE?揭秘3类典型资源浪费陷阱
  • 为 OpenClaw 配置 Taotoken 端点以接入统一大模型服务
  • 【AHC】HttpAsyncClient 与 async-http-client(AHC):谁是 Java 异步 HTTP 客户端的未来?
  • 为什么92%的Java低代码项目在v3.0版本崩溃?:揭秘元数据模型耦合、动态类加载泄漏与热更新失效根因
  • 外部 RFC 到 ABAP Platform 的 SNC 配置全景图,参数、认证链路与排障重点
  • OpenRocket:免费开源火箭设计与飞行仿真软件完整指南
  • 当不可能成为可能:我将 Mac OS X 移植到了 Nintendo Wii
  • 从PyTorch模型到TensorRT推理:在Windows上完整走通你的第一个加速Demo
  • 鸿蒙PC和App:都在走向 System
  • 深入浅出:图解TMS320F28377D ePWM八大子模块工作原理与配置逻辑
  • zynq7010和zynq7020的区别
  • 2026年三大AI模型深度横评:GPT-5Claude-4Gemini-2.5到底选谁
  • Hugging Face Transformers 加载模型时,那些容易被忽略但超有用的参数(cache_dir, proxies, revision 实战详解)
  • AMD锐龙处理器性能调优终极指南:如何使用SMU调试工具实现硬件级控制
  • FCN-32s/16s/8s效果差多少?用PASCAL VOC数据实测对比,聊聊语义分割的‘细节魔鬼’