快慢指针的应用

核心思想

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

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

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;
}
相关推荐
Tairitsu_H20 小时前
[LC优选算法#17] 链表 | 合并 K 个升序链表 | K个⼀组翻转链表
数据结构·算法·链表
东华万里1 天前
第32篇 数据结构入门 单链表的增删查改实现
数据结构·链表
文祐1 天前
C语言用双向链表实现单调递减(递增)队列
c语言·开发语言·链表
剑挑星河月1 天前
234. 回文链表
java·数据结构·算法·leetcode·链表
六bring个六1 天前
链表学习(常规链表)
数据结构·学习·链表
tachibana22 天前
hot100 回文链表(234)
java·网络·数据结构·leetcode·链表
青山木2 天前
Hot 100 --- LRU 缓存
java·数据结构·算法·leetcode·链表·缓存·哈希
小陈的代码之路3 天前
回文链表(LeetCode 234)C语言最佳解题思路
c语言·leetcode·链表
疯狂成瘾者20 天前
Java 集合 LinkedList 详解:链表结构、常用方法和队列使用
java·开发语言·链表
WL学习笔记20 天前
单项不带头不循环链表
数据结构·链表