您好,登录后才能下订单哦!
# 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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。