快慢指针的应用

核心思想

快慢指针的核心思想是利用两个移动速度不同的指针(通常快指针每次走两步,慢指针每次走一步,在遍历过程中通过他们的位置关系或相遇情况来解决问题。通常在数组和链表中有应用。(快指针用来探路,慢指针用来定位)

一、快慢指针在链表中的应用

1.判断链表是否有环

环形链表

通过快慢指针来判断链表是否有环。

思路:创建两个指针slow,fast,遍历链表。slow每次走一步,fast每次走两步,若链表有环,则快慢指针在进环后,快指针总会追上慢指针。若链表无环,则fast走向末尾。

c 复制代码
bool hasCycle(struct ListNode *head) {
    struct ListNode* slow,*fast;
    slow = fast = head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast = fast->next->next;
        if(slow==fast)
        {
            return true;
        }
    }
    return false;
}

拓展问题 :1.为什么一定会相遇,有没有可能会错过,永远追不上,请证明。

2.slow一次走1步,fast一次走3,4,5,步 n步,请证明。

证明:(1)

(2)

结论:一定能追上,N偶数第一轮就追上,N奇数,C-1偶数,第二轮追上。

2.返回链表入环的节点

环形链表2

c 复制代码
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *slow,*fast;
    slow = fast = head;
    while(fast&&fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow==fast)
        {
            struct ListNode *meet = slow;
            while(meet!=head)
            {
                meet = meet->next;
                head = head->next;
            }
            return meet;
        }
    }
    return NULL;
}

3.寻找链表的中点

链表的中间节点

通过快慢指针来返回链表中间节点,或返回第二个中间节点,可以通过快慢指针的方式,fast=2slow。(分为奇数和偶数个节点)

c 复制代码
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
    ListNode* slow, *fast;
    slow = fast = head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
    }
    return slow;
}

4.寻找倒数第k个节点

寻找倒数第k个节点

先让快指针走k步,,然后快慢指针同步移动,当快指针到达末尾时,慢指针指向的即为倒数第k个节点。

c 复制代码
typedef struct ListNode ListNode;
int kthToLast(struct ListNode* head, int k) {
    ListNode *slow,*fast;
    slow = fast=head;
    while(k--)
    {
        fast=fast->next;
    }
    while(fast)
    {
        slow=slow->next;
        fast=fast->next;
    }
    return slow->val;
}

5.随机链表的复制

随机链表的复制

c 复制代码
struct Node* copyRandomList(struct Node* head) {
	struct Node *cur = head;
    //拷贝节点插入在原节点的后面
    while(cur)
    {
        struct Node *copy = (struct Node*)malloc(sizeof(struct Node));

        copy->val = cur->val;
        copy->next = cur->next;
        cur->next = copy;

        cur = copy->next;
    }
    //控制random
    cur = head;
    while(cur)
    {
        struct Node* copy = cur->next;
        if(cur->random==NULL)
        {
            copy->random=NULL;
        }
        else{
            copy->random = cur->random->next;
        }
        cur = copy->next;
    }
    //把拷贝节点取下来尾插成为新链表,然后恢复原链表,不恢复也可以
    struct Node* copyhead,*copytail;
    copyhead = copytail = NULL;
    cur = head;
    while(cur)
    {
        struct Node* copy = cur->next;
        struct Node* next = copy->next;

        if(copytail==NULL)
        {
            copyhead = copytail = copy;
        }
        else
        {
            copytail->next = copy;
            copytail = copytail->next;
        }
        cur->next = next;
        cur=next;
    }
    return copyhead;
}



二、快慢指针在数组中的应用

1.移除元素

在有序数组中,慢指针指向"已处理区间"的末尾,快指针用于探索新元素,当快指针遇到不重复(或不等于目标值)的元素时,将其赋值给慢指针并移动慢指针。
移除数组中的重复元素

c 复制代码
int removeDuplicates(int* nums, int numsSize) {
    int slow = 0;
    for(int fast=1;fast<numsSize;fast++)
    {
        if(nums[fast]!=nums[slow])
        {
            slow++;
            nums[slow]=nums[fast];
        }
    }
    return slow+1;
}
相关推荐
二本咕咕-机械转码3 天前
FreeRTOS深入解析(八)IPC机制之FromISR详解
数据结构·单片机·链表
Nuanyt7 天前
LeetCode Hot 100 链表专题(五)· 2 题(Java)
java·算法·leetcode·链表
starzy199010 天前
Scala List操作:不可变链表的函数式美学
链表·list·scala
Nuanyt10 天前
LeetCode Hot 100 链表专题(四)· 3 题(Java)
java·算法·leetcode·链表·双指针
二本咕咕-机械转码10 天前
FreeRTOS深入解析(一)_链表与并发保护——哨兵循环链表、排序键游标、临界区与关调度
单片机·算法·链表
La Pulga11 天前
【FreeRTOS源码学习笔记】链表的实现
数据结构·笔记·stm32·mcu·链表·嵌入式·freertos
番茄味城市甜菜11 天前
数据结构:双向链表实现,链表与顺序表的对比
数据结构·链表
努力努力再努力wz11 天前
【Lua 入门系列】Lua数据结构:从 Table 出发,一文串联数组、链表、栈、队列、集合、映射与树的实现原理
数据结构·链表·lua
XiYang-DING12 天前
P4104.环形链表判断
数据结构·链表
Nuanyt13 天前
LeetCode Hot 100 链表专题2 3 题 (Java)
java·笔记·算法·leetcode·链表