快慢指针的应用

核心思想

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

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

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;
}
相关推荐
影视飓风TIM6 小时前
数据结构 | 链表超全笔记(单链表+双链表+高频算法题)
数据结构·笔记·链表
玖玥拾10 小时前
C/C++ 数据结构(六)链表迭代器与底层
c语言·数据结构·c++·链表·stl库
IronMurphy11 小时前
【算法五十八】23. 合并 K 个升序链表
数据结构·算法·链表
学计算机的计算基13 小时前
链表算法上篇:LeetCode 206/234/141/142/160/21 题解与易错点
java·笔记·算法·链表
Tisfy16 小时前
LeetCode 2095.删除链表的中间节点:两次遍历 / 一次遍历(快慢指针)
算法·leetcode·链表·题解·双指针
玖玥拾17 小时前
C/C++ 数据结构(五)链表的应用、对象池
c语言·数据结构·c++·链表·对象池·双向链表
2601_9618451517 小时前
花生十三网课网盘|百度网盘|下载
数据结构·算法·链表·贪心算法·排序算法·线性回归·动态规划
2601_9618451519 小时前
花生十三图推思维导图|图形推理|技巧
数据结构·算法·链表·贪心算法·排序算法·线性回归·动态规划
前进吧-程序员19 小时前
反转链表完全指南:辅助容器、三指针、头插法
数据结构·c++·链表
liulilittle1 天前
固定数组时间轮的槽过载优化:桶链表与批次执行
网络·数据结构·链表