数据结构:单链表的应用(力扣算法题)第二章

每题代码汇总:登录 - Gitee.com

上一章回顾:数据结构:单链表的应用(力扣算法题)第一章-CSDN博客

1.相交链表

160. 相交链表 - 力扣(LeetCode)

理解题意:

思路:

分别遍历两条单链表的长度,两条单链表长度相减,得到长度差的绝对值,让长一些的链表往前遍历长度差个结点,再让两条链表同步遍历,找相同结点。

注意:此处相同是指地址相同而不是值相同。

代码见下:

复制代码
typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    //求链表长度
    ListNode* pa = headA;
    ListNode* pb = headB;
    int sizeA = 0, sizeB = 0;
    while(pa)
    {
        ++sizeA;
        pa = pa->next;
    }
    while(pb)
    {
        ++sizeB;
        pb = pb->next;
    }
    //求链表长度差
    int gap = abs(sizeA - sizeB);//得到的是绝对值
    //定义长短链表
    //假设
    ListNode* shortlist = headA;
    ListNode* longlist = headB;
    if(sizeA > sizeB)
    {
        longlist = headA;
        shortlist = headB;
    }
    //长链表往前遍历
    while(gap--)
    {
        longlist = longlist->next;
    }
    //两链表一起走
    while(shortlist && longlist)
    {
        if(shortlist == longlist)
        {
            return shortlist;
        }
        shortlist = shortlist->next;
        longlist = longlist->next;
    }
    //不相交
    return NULL;
}

最终通过测试。

注意:

2.环形链表

141. 环形链表 - 力扣(LeetCode)

理解题意:

思路一:

使用快慢指针,慢指针一次走一步,快指针一次走两步,如果快指针和慢指针指向同一个结点,说明链表带环。

代码见下:

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

最终通过测试。

证明一:

证明为什么快指针每次走两步,慢指针每次走一步就可以相遇?

当slow刚入环时,其与fast的距离最远,假设为N,那么当slow走一步,fast走两步时,距离变为N-1,以此类推,最终N == 0。

证明二:

当快指针每次走3步,走4步......还能满足条件吗?

以每次走三步为例,并且需要对N进行分类讨论:

此时可以得到永远不能相遇的条件:N为奇数,C为偶数。那么,此条件正确吗?

此处假设环的周长为C,头结点到slow结点的长度为L。并且此时fast指针已经环绕X周。

依旧沿用上面的条件:3 * 慢指针路程 == 快指针路程

在追逐过程中,快慢指针所走过的路径长度:

fast:L + xC + C - N

slow:L

此时建立方程式:3L == L + xC + C - N

得:2L == (x+1)C - N,此时分两种情况:

情况1:偶数 = 偶数 - 偶数

情况2:偶数 = 奇数 - 奇数

此时可以证明上述得到的结论:N为奇数,C为偶数 不成立,则当快指针每次走3步,走4步......时,两指针依旧会相遇。

思路二:

使用快慢指针,快指针走3,4,5......步

代码如下:

复制代码
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode* head) {
    ListNode *slow, *fast;
    slow = fast = head;
    while (fast && fast->next) {
        slow = slow->next;
        int n = 4; // fast每次⾛三,四......步
        while (n--) {
            if (fast->next)
                fast = fast->next;
            else
                return false;
        }
        if (slow == fast) {
            return true;
        }
    }
    return false;
}

最终测试通过。

**总结:**虽然已经证明了快指针不论走多少步都可以满足在带环链表中相遇,但是在编写代码的时候 会有额外的步骤引入,涉及到快慢指针的算法题中通常习惯使用慢指针走⼀步快指针走两步的方式。

3.环形链表II

142. 环形链表 II - 力扣(LeetCode)

理解题意:

思路:

使用快慢指针,在环里一定会有相遇点,此时:相遇点到入环结点的距离 == 头结点到入环结点的距离。

代码如下:

复制代码
typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {
    //创建快慢指针
    ListNode* slow = head;
    ListNode* fast = head;
    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)
        {
            //相遇点:使用curr == slow,不动head,且使curr与slow一样每次走一步
            ListNode* curr = head;
            while(curr != slow)
            {
                curr = curr->next;
                slow = slow->next;
            }
            //入环第一个结点
            return curr;
        }
    }
    //不带环
    return NULL;
}

最终测试通过。

证明:

为什么在带环链表中,快慢指针相遇点到入环结点的距离 == 头结点到入环结点的距离?

此处,E为入环结点,M为相遇点,R为周长,L为头结点到入环结点的距离。

快慢指针在相遇点走的总路程:

slow = L + X

fast = L + X + nR,nR为fast指针的路程。

因为:2 * slow = fast

则:L = nR - X

L = (n - 1)R + R - X ,其中,L为头结点到入环结点的距离,R-X为相遇点到入环结点的距离。此时,(n-1)R可省略,不影响结果。

本章完。

相关推荐
玉木子5 小时前
机器学习(四)KNN算法-分类
算法·机器学习·分类
白仑色6 小时前
java中常见的几种排序算法
java·算法·排序算法
码了三年又三年6 小时前
【排序算法】冒泡 选排 插排 快排 归并
算法·排序算法
qq_433554546 小时前
C++ Bellman-Ford算法
开发语言·c++·算法
何妨重温wdys6 小时前
跳跃游戏(二):DFS 求解最少跳跃次数与最优路径
算法·深度优先
小莞尔6 小时前
【51单片机】【protues仿真】基于51单片机音乐盒(8首歌曲)系统
c语言·开发语言·单片机·嵌入式硬件·51单片机
智者知已应修善业6 小时前
【51单片机三路抢答器定时器1工作1外部中断1】2022-11-24
c语言·经验分享·笔记·嵌入式硬件·51单片机
劲镝丶7 小时前
51单片机的电子音乐盒 (详细教程)
c语言·c++·单片机·嵌入式硬件·51单片机
Natsume17108 小时前
音视频开发入门:FFmpeg vs GStreamer,新手该如何选择?
c语言·c++·ffmpeg·音视频·webrtc·实时音视频·视频编解码