1. 双指针算法核心思想解析
双指针算法是算法竞赛和面试中的常青树,其核心在于通过两个指针的协同移动来高效解决问题。与暴力解法相比,双指针通常能将时间复杂度从O(n²)降低到O(n),这种优化在数据量大的场景下尤为关键。
1.1 双指针的三种经典模式
对撞指针是最常见的双指针模式,两个指针分别从数据结构的首尾出发,向中间移动。这种模式特别适合解决有序数组的搜索和求和问题。例如在有序数组中寻找两数之和等于目标值的问题,对撞指针可以在O(n)时间内解决,而暴力解法需要O(n²)。
快慢指针模式通常用于链表相关的问题,如检测链表中的环。快指针每次移动两步,慢指针每次移动一步,当两者相遇时即可确定存在环。这种模式的时间复杂度也是O(n),空间复杂度仅为O(1),比使用哈希表存储节点更高效。
滑动窗口是处理子数组/子字符串问题的利器。通过维护一个动态变化的窗口,可以在O(n)时间内解决许多复杂问题。例如寻找满足条件的最长子字符串,滑动窗口可以避免重复计算,极大提升效率。
1.2 双指针适用的场景特征
双指针算法特别适合处理有序数据或可以排序的数据。排序后数据的单调性为双指针提供了移动的依据。例如在四数之和问题中,先对数组排序,才能确保指针移动的正确方向。
另一个适用场景是问题的解可以被分解为子问题。例如三数之和可以分解为固定一个数后求两数之和,四数之和可以分解为固定两个数后求两数之和。这种分解使得我们可以用双指针高效解决子问题。
空间复杂度受限的问题也常考虑双指针。相比哈希表等需要额外空间的方法,双指针通常只需要常数空间,这在空间要求严格的场景下是巨大优势。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 四数之和问题深度解析
2.1 问题转化与算法设计
四数之和问题要求找出数组中所有和为target的四元组。这个问题可以看作是两数之和和三数之和的扩展。核心思路是将四数之和转化为三数之和,再转化为两数之和。
具体实现采用排序+双层循环+双指针的策略。首先对数组排序,然后使用两层循环固定前两个数,最后用双指针寻找后两个数。这种转化使得时间复杂度从O(n⁴)降低到O(n³)。
关键点在于去重处理。由于要求解中不能有重复四元组,需要在每个层级跳过相同的元素。例如在第一层循环中,如果当前元素与前一个相同,则跳过;在第二层循环和双指针移动时也需类似处理。
2.2 代码实现与优化技巧
cpp复制class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
int n = nums.size();
for(int i=0; i<n-3; i++) {
if(i>0 && nums[i]==nums[i-1]) continue; // 去重
for(int j=i+1; j<n-2; j++) {
if(j>i+1 && nums[j]==nums[j-1]) continue; // 去重
long long t = (long long)target - nums[i] - nums[j];
int left = j+1, right = n-1;
while(left < right) {
long long sum = nums[left] + nums[right];
if(sum == t) {
res.push_back({nums[i],nums[j],nums[left],nums[right]});
// 跳过相同元素
while(left<right && nums[left]==nums[left+1]) left++;
while(left<right && nums[right]==nums[right-1]) right--;
left++; right--;
}
