1. 双指针算法核心思想解析
双指针技术是算法领域最基础也最高频的解题范式之一,尤其在处理线性数据结构时展现出惊人的效率。这种技术的本质是通过两个指针变量(索引变量)的协同移动来降低问题的时间复杂度,通常能将O(n²)的暴力解法优化到O(n)级别。
在实际编码面试中,约30%的数组/链表类题目都可以用双指针思路解决。我整理出双指针最常见的三种工作模式:
同向快慢指针:常用于链表环检测、数组去重等场景。快指针负责探索新元素,慢指针维护有效数据边界。例如在有序数组去重时,慢指针始终指向最后一个不重复元素,快指针扫描后续元素,发现新元素时慢指针才移动并更新值。
相向对撞指针:适用于有序数组的两数之和、三数之和等问题。一个指针从起点出发,另一个从终点出发,根据当前计算结果决定移动哪个指针。这种模式能有效避免暴力枚举带来的冗余计算。
滑动窗口指针:主要用于子串/子数组问题。通过维护一个动态变化的窗口(由左右指针界定),在遍历过程中调整窗口大小以满足特定条件。这种模式在字符串匹配、最小覆盖子串等问题中表现优异。
关键理解:双指针不是独立算法,而是一种通过指针运动规律来优化遍历效率的编程思想。其核心优势在于减少了不必要的重复计算。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 高频双指针题型深度剖析
2.1 有序数组的两数之和(LeetCode 167)
这是双指针最经典的入门题:给定升序排列的整数数组numbers,找出两个数使它们的和等于目标值target。题目保证存在唯一解。
java复制public int[] twoSum(int[] numbers, int target) {
int left = 0, right = numbers.length - 1;
while (left < right) {
int sum = numbers[left] + numbers[right];
if (sum == target) {
return new int[]{left + 1, right + 1};
} else if (sum < target) {
left++; // 和太小,左指针右移增大数值
} else {
right--; // 和太大,右指针左移减小数值
}
}
return new int[]{-1, -1};
}
复杂度分析:时间复杂度O(n),空间复杂度O(1)。相比哈希表解法,双指针无需额外空间,且能利用数组有序的特性。
易错点:
- 指针移动条件判断错误(应严格根据当前sum与target的关系决定移动方向)
- 忽略题目要求的1-based索引(需要返回left+1和right+1)
- 未处理无解情况(虽然题目保证有解,但实际编码应考虑防御性处理)
2.2 三数之和(LeetCode 15)
进阶版的两数之和问题:找出数组中所有和为0的三元组,且不能包含重复组合。这是面试最高频的题目之一。
java复制public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums); // 必须先排序
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < nums.length - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue; // 跳过重复元素
int left = i + 1, right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
res.add(Arrays.asList(nums[i], nums[left], nums[right]));
