数据结构算法题 2(力扣)——链表

本文介绍了如何使用快慢指针法解决链表的分隔、旋转和环形检测问题。作者详细解释了算法步骤,并给出了相应的C++代码示例,包括分区链表、旋转链表以及检测环形链表的入环节点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 分割链表(OJ链接

题目描述:给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有小于 x 的节点都出现在大于或等于 x 的节点之前

本题做法是:遍历链表将链表分为两部分,一部分的结点值小于特定值,另一部分的结点值大于或等于特定值,最后将两个链表链接起来。为了方便,下面将两部分链表称为大小链表。(值大于等于或小于特定值的链表)

为了便于将结点链接到大小链表中,采用带头结点的方式解决,可以避免大小链表为空或者不为空的讨论。

当遍历完链表后,可能出现链表成环的情况,因此需要将大链表的尾指针置空。

题解代码如下

typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x)
{
    if(head==NULL)
    {
        return NULL;
    }
    //创建两个带头链表
    ListNode* lesshead,*lesstail,*morehead,*moretail,*cur;
    lesshead=lesstail=(ListNode*)malloc(sizeof(ListNode));
    morehead=moretail=(ListNode*)malloc(sizeof(ListNode));
    cur=head;
    //遍历原链表
    while(cur)
    {
        if(cur->val<x)
        {
            lesstail->next=cur;
            lesstail=lesstail->next;
        }
        else
        {
            moretail->next=cur;
            moretail=moretail->next;
        }
        cur=cur->next;
    }
    //防止成环
    moretail->next=NULL;
    //首尾相连
    lesstail->next=morehead->next;
    ListNode* ret=lesshead->next;
    free(lesshead);
    free(morehead);
    return ret;
}

lesshead,lesstail,morehead,moretail分别是小链表和大链表的头尾指针。最初都指向头结点。

2. 旋转链表(OJ链接

题目描述:给你一个链表的头节点head ,旋转链表,将链表每个节点向右移动 k 个位置。

示例:
在这里插入图片描述
结果可以看作将后2个结点原封不动的挪到前面。因此需要找到倒数第k个结点,方法就是快慢指针法。

本题需要注意k的值,k可能很大,比如远大于结点的个数,当k等于结点的个数时,所有结点向右移动k个位置相当于不用移动,因此需要对k进行求余操作。

此题做法为:快慢指针法。首先先计算链表结点的数目,对k进行求余。fast指针先走k步,之后和慢指针以相同速度走,快指针为NULL时,慢指针指向的结点就是倒数第k个结点。为了避免成环,需要将倒数第k+1个结点的指针域置空,最后链接两部分链表即可。

一些需要注意的小的点就不多赘述了,比如链表为空或者只有一个结点,那么直接返回NULL或head即可。

题解代码如下:

struct ListNode* rotateRight(struct ListNode* head, int k) 
{
    //结点数为0
    if(head==NULL)
    return NULL;
    //结点数为1
    if(head->next==NULL)
    return head;

    struct ListNode* cur=head,*fast=head,*prev=head,*tail=head;
    int num=0;
    //计算链表结点个数
    while(cur)
    {
        num++;
        cur=cur->next;
    }
    k%=num;

    if(k==0)
    return head;
    //fast先走k步
    cur=head;
    while(k--)
    {
        fast=fast->next;
    }
    while(fast)
    {
        prev=cur;
        cur=cur->next;
        tail=fast;
        fast=fast->next;
    }
    //解环并链接首尾
    prev->next=NULL;
    tail->next=head;
    return cur;
}

指针含义:cur——指向新链表的头,prev——cur的前一个结点,tail——指向最后一个结点
对上述示例进行画图帮助理解代码,过程如下图
在这里插入图片描述
本题到此就结束咯

3. 环形链表(OJ链接

题目描述:给你一个链表的头节点 head ,判断链表中是否有环。

此题解法:快慢指针法,快指针一次走两步,慢指针一次走一步。两个指针指向同一个结点时,说明链表有环,快指针为NULL时说明链表没有环。

代码如下

bool hasCycle(struct ListNode *head) {
    struct ListNode* fast=head,*slow=head;
    while(fast!=NULL&&fast->next!=NULL)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)
        {
            return true;
        }
    }
    return false;
}

本题代码比较简单,但是这个思路是否正确需要验证,本质是一道数学题,验证过程如下图。

在这里插入图片描述

4. 环形链表2(OJ链接

题目描述:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

这个题可以看成上一题的后续,有环则找入环点。

这里先证明一个式子再写代码:有两个指针,一个指针从链表的头走,一个指针从相遇点走,并且同速走,那么当两个指针相遇时,相遇的那个结点就是入环点。

证明过程如下图
在这里插入图片描述
那么有了上述的结论再加上上一题的思路,本题就比较简单了。

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

链表部分的题目就到此为止了,后续就对栈队列等数据结构进行练习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值