算法 学习 双指针 2025年6月16日11:36:24

双指针:

使用两个指针协同遍历数组/链表,降低时间复杂度(通常从O(n²)优化到O(n))

典型应用场景
  1. 有序数组两数之和

  2. 反转数组

  3. 移除元素

双指针函数实现和调用示例
//有序数组的两数之和

#include 

/**
 * 在有序数组中查找两个数,使它们的和等于目标值
 * @param nums 有序数组
 * @param numsSize 数组大小
 * @param target 目标值
 * @param returnSize 返回数组大小(固定为2)
 * @return 两个数的索引数组(从1开始计数)
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
    int left = 0;
    int right = numsSize - 1;
    int* result = (int*)malloc(2 * sizeof(int));
    *returnSize = 2;
    
    while (left < right) {
        int sum = nums[left] + nums[right];
        printf("检查 %d + %d = %d\n", nums[left], nums[right], sum); // 流程展示
        
        if (sum == target) {
            result[0] = left + 1; // 题目要求从1开始计数
            result[1] = right + 1;
            return result;
        } else if (sum < target) {
            left++;
            printf("和太小,左指针右移 -> [%d]\n", left);
        } else {
            right--;
            printf("和太大,右指针左移 -> [%d]\n", right);
        }
    }
    
    return result; // 未找到时返回[0,0]
}

int main() {
    int nums[] = {2, 7, 11, 15};
    int target = 9;
    int returnSize;
    
    int* result = twoSum(nums, sizeof(nums)/sizeof(nums[0]), target, &returnSize);
    
    printf("\n最终结果: [%d, %d]\n", result[0], result[1]);
    free(result);
    return 0;
}

//流程
检查 2 + 15 = 17
和太大,右指针左移 -> [2]
检查 2 + 11 = 13
和太大,右指针左移 -> [1]
检查 2 + 7 = 9

最终结果: [1, 2]

滑动窗口:

维护一个动态变化的窗口,用常数时间更新窗口信息

典型应用场景
  1. 最长无重复子串

  2. 最小覆盖子串

  3. 长度最小的子数组

滑动窗口函数实现和调用示例
// 长度最小的子数组
#include 
#include 

/**
 * 寻找满足和≥target的最短连续子数组
 * @param nums 数组
 * @param numsSize 数组大小
 * @param target 目标和
 * @return 子数组长度(不存在返回0)
 */
int minSubArrayLen(int* nums, int numsSize, int target) {
    int left = 0;
    int sum = 0;
    int minLen = INT_MAX;
    
    for (int right = 0; right < numsSize; right++) {
        sum += nums[right];
        printf("窗口扩展: [%d,%d], sum=%d\n", left, right, sum);
        
        while (sum >= target) {
            int currentLen = right - left + 1;
            if (currentLen < minLen) {
                minLen = currentLen;
                printf("找到更小窗口: 长度=%d\n", minLen);
            }
            sum -= nums[left++]; // 收缩左边界
            printf("窗口收缩: [%d,%d], sum=%d\n", left, right, sum);
        }
    }
    
    return minLen == INT_MAX ? 0 : minLen;
}

int main() {
    int nums[] = {2, 3, 1, 2, 4, 3};
    int target = 7;
    
    int len = minSubArrayLen(nums, sizeof(nums)/sizeof(nums[0]), target);
    printf("\n最小长度: %d\n", len);
    
    return 0;
}

//流程
窗口扩展: [0,0], sum=2
窗口扩展: [0,1], sum=5
窗口扩展: [0,2], sum=6
窗口扩展: [0,3], sum=8
找到更小窗口: 长度=4
窗口收缩: [1,3], sum=6
窗口扩展: [1,4], sum=10
找到更小窗口: 长度=4
窗口收缩: [2,4], sum=7
找到更小窗口: 长度=3
窗口收缩: [3,4], sum=6
窗口扩展: [3,5], sum=9
找到更小窗口: 长度=3
窗口收缩: [4,5], sum=7
找到更小窗口: 长度=2
窗口收缩: [5,5], sum=3

最小长度: 2

快慢指针

用不同速度移动的两个指针解决链表/数组问题

典型应用场景
  1. 检测链表环

  2. 寻找链表中点

  3. 寻找重复数

快慢指针函数实现和调用示例
//检测链表环

#include 
#include 

// 链表节点定义
struct ListNode {
    int val;
    struct ListNode *next;
};

/**
 * 检测链表是否有环
 * @param head 链表头节点
 * @return 是否有环
 */
bool hasCycle(struct ListNode *head) {
    if (head == NULL) return false;
    
    struct ListNode *slow = head;
    struct ListNode *fast = head->next;
    int step = 1;
    
    while (fast != NULL && fast->next != NULL) {
        printf("步数%d: 慢指针=%d, 快指针=%d\n", 
               step++, slow->val, fast->val);
        
        if (slow == fast) {
            printf("快慢指针相遇于%d\n", slow->val);
            return true;
        }
        
        slow = slow->next;         // 慢指针走1步
        fast = fast->next->next;   // 快指针走2步
    }
    
    return false;
}

int main() {
    // 构建测试链表: 1->2->3->4->2(形成环)
    struct ListNode node1 = {1, NULL};
    struct ListNode node2 = {2, NULL};
    struct ListNode node3 = {3, NULL};
    struct ListNode node4 = {4, NULL};
    
    node1.next = &node2;
    node2.next = &node3;
    node3.next = &node4;
    node4.next = &node2; // 形成环
    
    bool result = hasCycle(&node1);
    printf("\n检测结果: %s\n", result ? "有环" : "无环");
    
    return 0;
}

//流程
步数1: 慢指针=1, 快指针=2
步数2: 慢指针=2, 快指针=4
步数3: 慢指针=3, 快指针=2
步数4: 慢指针=4, 快指针=4
快慢指针相遇于4

检测结果: 有环

技术 典型场景 时间复杂度 空间复杂度 核心操作
双指针 有序数组操作 O(n) O(1) 左右指针向中间移动
滑动窗口 连续子数组/子串问题 O(n) O(1) 动态维护窗口边界
快慢指针 链表环/中点问题(链表结构分析) O(n) O(1) 不同速度移动指针

 

你可能感兴趣的:(基础编程算法,学习,学习,双指针,算法,滑动窗口,快慢指针)