news 2026/7/13 17:54:29

双指针算法详解:从入门到精通(Java版)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
双指针算法详解:从入门到精通(Java版)

目录

一、什么是双指针?

1.1 对撞指针(左右指针)

1.2 快慢指针(龟兔赛跑算法)

二、经典题目实战

2.1 移动零(LeetCode 283)

2.2 复写零(LeetCode 1089)

2.3 快乐数(LeetCode 202)

2.4 盛水最多的容器(LeetCode 11)

2.5 有效三角形的个数(LeetCode 611)

2.6 和为s的两个数字(剑指Offer 57)

2.7 三数之和(LeetCode 15)

2.8 四数之和(LeetCode 18)

三、双指针算法总结


一、什么是双指针?

双指针是一种常用的算法技巧,通过使用两个指针在数组或链表等数据结构上进行移动,来解决特定问题。根据指针移动方式的不同,双指针主要分为两种形式:

1.1 对撞指针(左右指针)

对撞指针从两端向中间移动。一个指针从最左端开始,另一个从最右端开始,然后逐渐往中间逼近。

终止条件

  • left == right:两个指针指向同一个位置

  • left > right:两个指针错开

1.2 快慢指针(龟兔赛跑算法)

快慢指针使用两个移动速度不同的指针在序列结构上移动。通常在一次循环中,慢指针每次移动一位,快指针每次移动两位。

适用场景

  • 处理环形链表或数组

  • 研究出现循环往复的问题


二、经典题目实战

2.1 移动零(LeetCode 283)

题目描述:给定一个数组nums,将所有 0 移动到数组末尾,同时保持非零元素的相对顺序。

算法思路

使用两个指针curdestcur用于遍历数组,dest指向非零元素序列的最后一个位置。

class Solution { public void moveZeroes(int[] nums) { for (int cur = 0, dest = -1; cur < nums.length; cur++) { if (nums[cur] != 0) { // 处理非零元素 dest++; int temp = nums[dest]; nums[dest] = nums[cur]; nums[cur] = temp; } } } }

核心思想:遍历过程中,使[0, dest]区间全为非零元素,[dest+1, cur-1]区间全为零。


2.2 复写零(LeetCode 1089)

题目描述:将数组中每个零都复写一遍,其余元素向右平移,不能超过数组长度。

算法思路

采用"从后向前"的复写策略,避免从前向后复写时数据被覆盖。

class Solution { public void duplicateZeros(int[] arr) { int cur = 0, dest = -1, n = arr.length; // 1. 先找到最后一个需要复写的数 while (cur < n) { if (arr[cur] == 0) { dest += 2; } else { dest += 1; } if (dest >= n - 1) break; cur++; } // 2. 处理边界情况 if (dest == n) { arr[n - 1] = 0; cur--; dest -= 2; } // 3. 从后向前完成复写操作 while (cur >= 0) { if (arr[cur] != 0) { arr[dest--] = arr[cur--]; } else { arr[dest--] = 0; arr[dest--] = 0; cur--; } } } }

2.3 快乐数(LeetCode 202)

题目描述:判断一个数是否为快乐数。快乐数定义为:每次将该数替换为它每个位置上的数字的平方和,重复这个过程直到变为1,或进入无限循环。

算法思路

使用快慢指针检测循环。如果相遇位置的值是1,则是快乐数;否则不是。

class Solution { public boolean isHappy(int n) { int slow = n, fast = bitSum(n); while (slow != fast) { slow = bitSum(slow); fast = bitSum(bitSum(fast)); } return slow == 1; } private int bitSum(int n) { int sum = 0; while (n != 0) { int t = n % 10; sum += t * t; n /= 10; } return sum; } }

2.4 盛水最多的容器(LeetCode 11)

题目描述:找出两条垂线,使它们与x轴构成的容器能容纳最多的水。

算法思路

使用对撞指针,每次移动较短的边界,因为移动较长边界只会使容积变小。

class Solution { public int maxArea(int[] height) { int left = 0, right = height.length - 1, ret = 0; while (left < right) { int v = Math.min(height[left], height[right]) * (right - left); ret = Math.max(ret, v); if (height[left] < height[right]) { left++; } else { right--; } } return ret; } }

2.5 有效三角形的个数(LeetCode 611)

题目描述:返回数组中可以组成三角形三条边的三元组个数。

算法思路

先排序,固定最长边,使用对撞指针在剩余区间中寻找满足两边之和大于第三边的组合。

class Solution { public int triangleNumber(int[] nums) { // 1. 排序 Arrays.sort(nums); // 2. 利用双指针解决问题 int ret = 0, n = nums.length; for (int i = n - 1; i >= 2; i--) { // 固定最大的数 int left = 0, right = i - 1; while (left < right) { if (nums[left] + nums[right] > nums[i]) { ret += right - left; right--; } else { left++; } } } return ret; } }

2.6 和为s的两个数字(剑指Offer 57)

题目描述:在递增排序的数组中查找两个数,使它们的和等于目标值。

算法思路

利用数组有序的特性,使用对撞指针,根据当前和与目标值的大小关系移动指针。

class Solution { public int[] twoSum(int[] nums, int target) { int left = 0, right = nums.length - 1; while (left < right) { int sum = nums[left] + nums[right]; if (sum > target) { right--; } else if (sum < target) { left++; } else { return new int[]{nums[left], nums[right]}; } } return new int[]{-1, -1}; } }

2.7 三数之和(LeetCode 15)

题目描述:找出数组中所有和为0且不重复的三元组。

算法思路

先排序,固定一个数,在其后的区间中使用双指针找两数之和等于目标值,注意去重。

class Solution { public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> ret = new ArrayList<>(); // 1. 排序 Arrays.sort(nums); // 2. 利用双指针解决问题 int n = nums.length; for (int i = 0; i < n; ) { // 固定数 a if (nums[i] > 0) break; // 小优化 int left = i + 1, right = n - 1, target = -nums[i]; while (left < right) { int sum = nums[left] + nums[right]; if (sum > target) { right--; } else if (sum < target) { left++; } else { ret.add(Arrays.asList(nums[i], nums[left], nums[right])); left++; right--; // 去重操作 while (left < right && nums[left] == nums[left - 1]) left++; while (left < right && nums[right] == nums[right + 1]) right--; } } // 去重 i++; while (i < n && nums[i] == nums[i - 1]) i++; } return ret; } }

2.8 四数之和(LeetCode 18)

题目描述:找出数组中所有和为target且不重复的四元组。

算法思路

在三数之和的基础上再套一层循环,固定两个数,使用双指针找剩余两数。

class Solution { public List<List<Integer>> fourSum(int[] nums, int target) { List<List<Integer>> ret = new ArrayList<>(); // 1. 排序 Arrays.sort(nums); // 2. 利用双指针解决问题 int n = nums.length; for (int i = 0; i < n; ) { // 固定数 a for (int j = i + 1; j < n; ) { // 固定数 b int left = j + 1, right = n - 1; long aim = (long)target - nums[i] - nums[j]; while (left < right) { int sum = nums[left] + nums[right]; if (sum > aim) { right--; } else if (sum < aim) { left++; } else { ret.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right])); left++; right--; // 去重 while (left < right && nums[left] == nums[left - 1]) left++; while (left < right && nums[right] == nums[right + 1]) right--; } } // 去重 j++; while (j < n && nums[j] == nums[j - 1]) j++; } // 去重 i++; while (i < n && nums[i] == nums[i - 1]) i++; } return ret; } }

三、双指针算法总结

题目

指针类型

关键技巧

移动零

快慢指针

数组分块,维护非零区间

复写零

前后指针

从后向前避免覆盖

快乐数

快慢指针

检测循环

盛水容器

对撞指针

移动较短边界

三角形个数

对撞指针

排序后固定最长边

两数之和

对撞指针

利用有序性

三数之和

对撞指针

固定一个数+去重

四数之和

对撞指针

固定两个数+去重

双指针的核心思想:通过分析问题的二段性,利用指针移动来减少不必要的枚举,将时间复杂度从 O(n²) 优化到 O(n)。

使用技巧

  1. 对撞指针常用于有序数组或字符串

  2. 快慢指针常用于环形结构或需要检测循环的场景

  3. 注意边界条件和指针移动的时机

  4. 涉及去重问题时,注意跳过重复元素

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

Ornith-1.0-9B:解决智能编码代理部署复杂性的开源方案

Ornith-1.0-9B&#xff1a;解决智能编码代理部署复杂性的开源方案 【免费下载链接】Ornith-1.0-9B 项目地址: https://ai.gitcode.com/hf_mirrors/deepreinforce-ai/Ornith-1.0-9B 在当今快速发展的AI开发领域&#xff0c;智能编码代理已成为提升开发效率的关键工具。然…

作者头像 李华
网站建设 2026/7/13 17:51:02

AutoBE与Claude Code协作:生成后代码维护的最佳实践

AutoBE与Claude Code协作&#xff1a;生成后代码维护的最佳实践 【免费下载链接】autobe AI Vibe Coding Agent of TS backend server, enhanced by compiler skills, generating 100% working code 项目地址: https://gitcode.com/gh_mirrors/au/autobe AutoBE作为一款…

作者头像 李华
网站建设 2026/7/13 17:48:15

从噪声到艺术:深入解析扩散模型的核心原理与实战应用

1. 扩散模型&#xff1a;从物理现象到AI绘画革命第一次听说扩散模型时&#xff0c;我正盯着咖啡杯里逐渐散开的奶渍发呆。这种看似平常的物理现象&#xff0c;后来竟成了颠覆AI生成领域的关键灵感。扩散模型&#xff08;Diffusion Model&#xff09;作为当前最火的生成式AI技术…

作者头像 李华
网站建设 2026/7/13 17:47:45

揭秘www.sh框架:用Shell脚本实现路由与模板引擎的神奇方法

揭秘www.sh框架&#xff1a;用Shell脚本实现路由与模板引擎的神奇方法 【免费下载链接】www.sh Web framework in Bash 项目地址: https://gitcode.com/gh_mirrors/ww/www.sh www.sh 是一款颠覆认知的实验性Web框架&#xff0c;它以Shell脚本为核心&#xff0c;实现了传…

作者头像 李华
网站建设 2026/7/13 17:44:48

调色指南:DaVinci Resolve 20下载与详细安装教程分享

如大家所熟悉的&#xff0c;DaVinci Resolve是一站式专业影视后期全流程软件‌工具&#xff0c;集剪辑、调色、视觉特效&#xff08;Fusion&#xff09;、音频后期&#xff08;Fairlight&#xff09;及照片处理于一体&#xff0c;以‌好莱坞级调色能力‌和‌节点式非破坏性工作…

作者头像 李华