单链表专题(快慢指针的运用等与综合题目)

目录

一.普通快慢 

一.返回倒数第K个结点

二.相交链表

三.回文链表​编辑

二.循环单链表中快慢的使用

一.判断是否为环形链表

二.返回环的初始结点

三.复制单链表(综合题目)

思路

一.在当前链表后面进行copy

二.对random进行复制

三.将原链表剪下来


一.普通快慢 

一.返回倒数第K个结点

面试题 02.02. 返回倒数第 k 个节点 - 力扣(LeetCode)

思路很简单就是先让fast指针先走k步,那么slow也就是慢指针只会走N-K步(N为总长度),

我们返回的也是slow走(N-K)步的位置

代码如下 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

int kthToLast(struct ListNode* head, int k)
{
    //先让fast指针走K步
    struct ListNode* fast=head;
    struct ListNode* slow=head;

    while(k--)
    {
        fast=fast->next;
    }
    while(fast)
    {
        fast=fast->next;
        slow=slow->next;
    }
    return slow->val;
}

二.相交链表

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

解答过程和思路很简单就是先让长的走到与短的相等最后一起走如果相等则返回相交链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode; 
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    //进行遍历找到最长链表
    int lenthA=0;
    int lenthB=0;
    ListNode* curA=headA;
    ListNode* curB=headB;
    while(curA)
    {
        ++lenthA;
        curA=curA->next;
    }
    while(curB)
    {
        ++lenthB;
        curB=curB->next;
    }
    //找到长链表重新赋值
    if(lenthB>lenthA)
    {
        curA=headB;
        curB=headA;
    }
    else
    {
        curA=headA;
        curB=headB;
    }
    int temp=abs(lenthA-lenthB);
    while(temp--)//先让长的链表走到相等位置
    {
        curA=curA->next;
    }
    while(curA&&curB)
    {
        if(curA==curB)
        return curA;
        curA=curA->next;
        curB=curB->next;
    }
    return NULL;
}


三.回文链表

链表的回文结构_牛客题霸_牛客网 (nowcoder.com)z

这里我们将会运用到两个链表的知识,一个是链表的反转,一个是运用快慢指针来寻找中间值

首先我们要思考怎么比较回文结构,我觉得可以这样来将前面的与后面的一一进行比较,直到中间结束,如果有一个不相等返回false不是回文

但是前面与后面相比比较复杂所有我们先将其(从中间开始)进行反转

//有啦下以上的思考我们来做这道题

如果我们想要将链表进行反转肯定要先找到中间的位置,运用快慢指针找到中间位置

找到后进行反转,代码如下

ListNode* FindMid(ListNode* head)//运用快慢指针找到中间位置
{
    ListNode* fast=head;
    ListNode* slow=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
    }
    return slow;
}
ListNode* ReverseList(ListNode* head)//找到位置后进行反转
{
    ListNode* pre=NULL;
    ListNode* cur=head;
    ListNode* next=head->next;
    while(cur)
    {
        cur->next=pre;
        pre=cur;
        cur=next;
        if(next)
        next=next->next;
    }
    return pre;
}
class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        if(A==NULL)
        return false;
        ListNode* mid=FindMid(A);//保存中间位置
        ListNode* reallyMid=ReverseList(mid);//反转后返回新的中间值
        ListNode* head=A;
        while(head&&reallyMid)
        {
            if(head->val!=reallyMid->val)//进行比较
            {
                return false;
            }
            head=head->next;
            reallyMid=reallyMid->next;
        }
        return true;
    }
};

二.循环单链表中快慢的使用

一.判断是否为环形链表

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

//一道经典的快慢指针题目板子题详情介绍可看我的这篇 下面那道题也是

带环单链表的追击问题(快慢指针的运用)-CSDN博客

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) 
{
    if(head==NULL||head->next==NULL)
    return false;
    struct ListNode *fast=head->next->next;
    struct ListNode *slow=head->next;
    while(fast&&fast->next)
    {
       
        if(fast==slow)
        {
            return true;
        }
         fast=fast->next->next;
        slow=slow->next;
    }
    return false;
}

二.返回环的初始结点

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

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) 
{
    if(head==NULL||head->next==NULL)
    {
        return NULL;
    }
    struct ListNode *fast=head;
    struct ListNode *slow=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            fast=head;
            while(1)
            {
                if(fast==slow)
                {
                    return fast;
                }
                fast=fast->next;
                slow=slow->next;
            }
        }
    }
    return NULL;
    
}

三.复制单链表(综合题目)

138. 随机链表的复制 - 力扣(LeetCode)

因为新生成的链表要指向新生成的链表所以有这样的一个巧妙做法

//这道题其实就三个思路

思路

一.在当前链表后面进行copy

这里运用了一个相当巧妙的做法,在原链表的后面进行一次copy原链表,将next指针与val值进行赋值,random先不管

二.对random进行复制

c然后可以对新链表的random赋值,(copy->random=current->random->next)因为random就在久链表的random->next

三.将原链表剪下来

将原链表剪下来即可


typedef struct Node Node;
struct Node* copyRandomList(struct Node* head) 
{
    //在当前的链表后面进行copy链表
    if(head==NULL)
    return NULL;
    Node *cur=head;
    while(cur)
    {
        Node* newnode=(Node*)malloc(sizeof(Node));
        Node* next=cur->next;
        newnode->val=cur->val;
        newnode->next=cur->next;
        cur->next=newnode;
        cur=next;
    }
    //进行random的赋值
    cur =head;
    while(cur)
    {
        if(cur->random==NULL)
        {
            cur->next->random=NULL;
        }
        else
        {
            cur->next->random=cur->random->next;
        }
        cur=cur->next->next;
    }
    //将原链表剪下来
    cur =head;
    Node* newHead=(Node*)malloc(sizeof(Node));
    Node* tail=newHead;
    while(cur)
    {
        tail->next=cur->next;
        cur=cur->next->next;
        tail=tail->next;
    }
    return newHead->next;
}

由于个人精力有限,如有不对欢迎指出让我们一起进步吧!!

小bit!!!

  • 44
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值