您好,登录后才能下订单哦!
# C语言双指针算法怎么用
## 一、什么是双指针算法
双指针算法(Two Pointers Technique)是C语言中一种高效的算法策略,通过在数组或链表中使用两个指针协同工作来解决问题。这两个指针可以同向移动(快慢指针)或相向移动(对撞指针),能够将某些需要嵌套循环的问题优化为单次遍历。
### 核心特点
1. **空间效率**:通常只需要O(1)的额外空间
2. **时间优化**:将O(n²)复杂度降为O(n)
3. **逻辑清晰**:通过指针运动直观表达算法逻辑
## 二、双指针的三种经典模式
### 1. 对撞指针(首尾指针)
```c
int left = 0, right = len - 1;
while(left < right){
    // 根据条件移动其中一个指针
    if(condition) left++;
    else right--;
}
典型应用场景: - 有序数组的二分查找 - 两数之和(LeetCode 167) - 反转数组/字符串
int slow = 0, fast = 0;
while(fast < len){
    if(condition){
        // 慢指针有条件移动
        arr[slow++] = arr[fast];
    }
    fast++;
}
典型应用场景: - 移除有序数组重复项(LeetCode 26) - 链表中环的检测 - 寻找链表中点
int left = 0, right = 0;
while(right < len){
    window.add(arr[right]);
    while(window满足收缩条件){
        // 更新结果
        window.remove(arr[left++]);
    }
    right++;
}
典型应用场景: - 最小覆盖子串(LeetCode 76) - 长度最小的子数组(LeetCode 209) - 无重复字符的最长子串
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    int left = 0, right = numsSize - 1;
    int* res = (int*)malloc(2 * sizeof(int));
    *returnSize = 2;
    
    while(left < right){
        int sum = nums[left] + nums[right];
        if(sum == target){
            res[0] = left + 1;
            res[1] = right + 1;
            return res;
        }else if(sum < target){
            left++;
        }else{
            right--;
        }
    }
    return res;
}
int removeElement(int* nums, int numsSize, int val){
    int slow = 0;
    for(int fast = 0; fast < numsSize; fast++){
        if(nums[fast] != val){
            nums[slow++] = nums[fast];
        }
    }
    return slow;
}
int maxArea(int* height, int heightSize){
    int left = 0, right = heightSize - 1;
    int max = 0;
    while(left < right){
        int area = (right - left) * fmin(height[left], height[right]);
        if(area > max) max = area;
        if(height[left] < height[right]) left++;
        else right--;
    }
    return max;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
    // 排序预处理
    qsort(nums, numsSize, sizeof(int), cmp);
    
    int** res = (int**)malloc(20000 * sizeof(int*));
    *returnColumnSizes = (int*)malloc(20000 * sizeof(int));
    *returnSize = 0;
    
    for(int i = 0; i < numsSize - 2; i++){
        if(i > 0 && nums[i] == nums[i-1]) continue;
        
        int left = i + 1, right = numsSize - 1;
        while(left < right){
            int sum = nums[i] + nums[left] + nums[right];
            if(sum == 0){
                res[*returnSize] = (int*)malloc(3 * sizeof(int));
                res[*returnSize][0] = nums[i];
                res[*returnSize][1] = nums[left];
                res[*returnSize][2] = nums[right];
                (*returnColumnSizes)[*returnSize] = 3;
                (*returnSize)++;
                
                // 跳过重复元素
                while(left < right && nums[left] == nums[left+1]) left++;
                while(left < right && nums[right] == nums[right-1]) right--;
                left++;
                right--;
            }else if(sum < 0){
                left++;
            }else{
                right--;
            }
        }
    }
    return res;
}
struct ListNode* middleNode(struct ListNode* head){
    struct ListNode *slow = head, *fast = head;
    while(fast != NULL && fast->next != NULL){
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}
预处理的重要性:
指针移动条件:
// 经典移动条件判断模式
if(满足条件A){
   left++;
}else if(满足条件B){
   right--;
}else{
   // 处理找到解的情况
}
边界处理陷阱:
循环终止条件:
while(left <= right) 与 while(left < right)的区别fast != NULL vs fast->next != NULL| 问题类型 | 暴力解法复杂度 | 双指针复杂度 | 优化幅度 | 
|---|---|---|---|
| 两数之和 | O(n²) | O(n) | 降一阶 | 
| 链表环检测 | O(n²) | O(n) | 降一阶 | 
| 滑动窗口问题 | O(n²) | O(n) | 降一阶 | 
| 三数之和 | O(n³) | O(n²) | 降一阶 | 
// 正确写法 while(left <= right && left < len && right >= 0){ // … }
2. **死循环问题**:
   - 确保每次循环至少有一个指针会移动
   - 添加循环次数计数器作为保护
3. **多指针同步**:
   ```c
   // 三指针示例(颜色分类问题)
   int low = 0, mid = 0, high = len - 1;
   while(mid <= high){
       if(nums[mid] == 0){
           swap(&nums[low++], &nums[mid++]);
       }else if(nums[mid] == 1){
           mid++;
       }else{
           swap(&nums[mid], &nums[high--]);
       }
   }
字符串处理:
链表高级操作:
特殊数据结构:
掌握要点:
刷题路线建议: “`
”`
调试建议:
双指针算法体现了C语言指针操作的精华,通过大量练习可以培养出优秀的算法直觉。建议从简单问题入手,逐步过渡到复杂场景的应用。 “`
该文章共计约2150字,包含: - 8个核心章节 - 5个完整代码示例 - 3种模式对比 - 4个优化技巧 - 2个实用表格 - 多个注意事项提示
文章结构符合技术文档规范,代码示例采用标准C语法,关键点配有中文注释,适合不同水平开发者学习参考。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。