链表刷题笔记

笔记

1.移除链表元素

111

这道题目有什么思路吗?

画图

输入图片说明

代码实现
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode*prev=NULL,*cur=head;
while(cur!=NULL)
{
    if(cur->val==val)
    {
        if(cur==head)
        {
            cur=head->next;
            free(head);
            head=cur;
        }
        else
        {
            prev->next=cur->next;
            free(cur);
            cur=prev->next;
        }
    }
    else
    {
        prev=cur;
        cur=cur->next;
    }
}
return head;

}

2.反转链表

输入图片说明

      1. 这里是列表文本
代码实现1:利用头插的方法进行巧妙的解题,但是他需要创建新的newnode,空间复杂度较大

输入图片说明

代码实现2:直接暴力反转

用三个指针n1 n2 n3进行暴力反转
n1指向n2的前驱,解决找前一个节点的问题 n2则代替head的节点进行迭代,n3指向n2的后驱,来控制循环的中断

画图

输入图片说明

实现:

输入图片说明

3.寻找链表的中间节点

题目:输入图片说明
代码实现:(利用快慢指针步长差距来解决问题)

输入图片说明

4.寻找链表中的倒数第k个节点

题目:

输入图片说明

特殊情况需要注意:k哪些情况下是返回空指针的?

a.当这个链表为空的时候,或者k<=0的时候,是没有倒数元素的

b.当k>n的时候,这种正着数的 元素遍历算法就会失效

思路1:通过倒数第k个求出正数是第(n-k)个元素,假设链表为 1 2 3 4 5 倒数第二个则是4 ,那么n为链表元素个数5,正数则需要往后移动(5-2)个指针,找到4
代码实现:
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(k<=0||!pListHead)
        {
            return NULL;
        }
        int n=0;
        ListNode* cur=pListHead;
        while(cur)
        {
            cur=cur->next;
            n++;
        }
        if(n<k)
        {
            return NULL;
        }
        n-=k;
        while(n--)
        {
            pListHead=pListHead->next;
        }
        return pListHead;
    }
};
思路二:假设链表为 1 2 3 4 5 ,需要找到倒数第二个元素 4 ,则设置快慢指针,假设在链表5个元素 1 2 3 4 5 的情况下 ,假设k=2,则4 为所求,slow和fast的组合,让fast比slow先走k步 (1 3)(2 4)(3 5)(4 null),当fast指针移动到null时,终止循环,slow指向的就是倒数第k个元素。如图所示

输入图片说明

代码实现:
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(k<=0||!pListHead)
        {
            return NULL;
        }
        ListNode*slow=pListHead;
        ListNode*fast=pListHead;
        while(k--)
        {
            if(fast)
            {
                fast=fast->next;
            }
           else
           {
               return NULL;   
           }
               
        }
        while(fast!=NULL)
        {
            slow=slow->next;
            fast=fast->next;
        }
        return slow;
}
};

5.合并两个有序链表

题目:

输入图片说明

需要考虑的问题:

1.两个链表都为空的情况
2.两个链表其中一个为空
3.其中任意一个链表先遍历完

思路一:利用尾部插入,没什么技巧
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    if(l1==NULL)
    {
    return l2;
    }
    if(l2==NULL)
    {
    return l1;
    }
    struct ListNode* newhead=NULL,*newtail=NULL;
    if(l1->val>=l2->val)
    {
        newhead=newtail=l2;
        l2=l2->next;
    }
    else
    {
        newhead=newtail=l1;
        l1=l1->next;
    }
    while(l1&&l2)
    {
        if(l1->val>l2->val)
        {
            newtail->next=l2;
            newtail=l2;
            l2=l2->next;
        }
        else
        {
            newtail->next=l1;
            newtail=l1;
            l1=l1->next;
        }
    }
    if(l1)
    newtail->next=l1;
    if(l2)
    newtail->next=l2;
    return newhead;
}
思路二:利用迭代在原链表中进行,减少空间复杂度为o(1),创建哨兵位的头节点
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    if(l1==NULL)
    {
    return l2;
    }
    if(l2==NULL)
    {
    return l1;
    }
    struct ListNode* newhead=NULL,*newtail=NULL;
    newhead=newtail=(struct ListNode*)malloc(sizeof(struct ListNode));
    //记得malloc要带struct,不然会越界
    while(l1&&l2)
    {
        if(l1->val>l2->val)
        {
            newtail->next=l2;
            newtail=l2;
            l2=l2->next;
        }
        else
        {
            newtail->next=l1;
            newtail=l1;
            l1=l1->next;
        }
    }
    if(l1)
    newtail->next=l1;
    if(l2)
    newtail->next=l2;
    struct ListNode* list=newhead->next;
    free(newhead);
    return list;
}

6.链表分割

输入图片说明

思路:用lessHead greatHead 分成两个链表,在将greatHead尾插到lessHead上
class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        ListNode*lessHead,*lessTail,*greatHead,*greatTail;
        lessHead=lessTail=(struct ListNode*)malloc(sizeof(struct ListNode));
        lessTail->next=NULL;
        greatHead=greatTail=(struct ListNode*)malloc(sizeof(struct ListNode));
        greatTail->next=NULL;
        struct ListNode* cur=pHead;
        while(cur)
        {
            if(cur->val>x)
            {
                greatTail->next=cur;
                greatTail=cur;
            }
            else
            {
                lessTail->next=cur;
                lessTail=cur;
            }
            cur=cur->next;
        }
        lessTail->next=greatHead->next;
        greatTail->next= NULL;
        struct ListNode* newHead=lessHead->next;
        free(lessHead);
        free(greatHead);
        return newHead;
        // write code here
    }
};

链表的回文结构

思路:1.先用快慢指针得出链表的中间元素所在
2.题目要求空间复杂度为o(1),所以只能递归的方式(双指针)将链表从中间位置以后进行逆转
3.从开始的head,命名为curA 和 逆置开始的节点 curB一一比较,从而得出结果
struct ListNode* midList(struct ListNode*head)
{ 
    struct ListNode*slow=head,*fast=head;
        while(fast&&fast->next)
        {
            slow=slow->next;
            fast=fast->next;
        }
        return slow;
}

struct ListNode* reverseList(struct ListNode *pos)
{
    struct ListNode*pre=NULL,*cur=pos;
        while(cur)
        {
            struct ListNode*next=cur->next;
            cur->next=pre;
            pre=cur;
            cur=next;
        }
        return pre;
}

class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        struct ListNode* mid=midList(A);
        struct ListNode* rHead=reverseList(mid);
        struct ListNode* curA=A;
        struct ListNode* curB=rHead;
        while(curA&&curB)
        {
            if(curA->val!=curB->val)
            {
                return false;
            }
            else
            {
                curA=curA->next;
                curB=curB->next;
            }
        }
        return true;
    }
};

7.相交链表的节点

输入图片说明输入图片说明

思路:1.通过两个链表的尾节点判断是否相交
2.通过两个链表的步长差,让长的链表先走步长,再一一比较
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode* tail1=headA;
    struct ListNode* tail2=headB;
    int len1=1;
    while(tail1->next)
//为什么判断条件是tail->next 而不是tail
//因为我们需要得到tail,如果判断条件为tail,它总会变为null
    {
        tail1=tail1->next;
        ++len1;
    }
    int len2=1;
    while(tail2->next)
    {
        tail2=tail2->next;
        ++len2;
    }
    if(tail1!=NULL&& tail2!=NULL &&tail1!=tail2)
    {
        return NULL;
    }
    int gap=abs(len1-len2);
    //if(tail1!=NULL && tail2!=NULL && tail2->val==tail1->val)
    //有交点呀
        struct ListNode* longList=headA;
        struct ListNode* shortList=headB;
        if(len1<len2)
        {
            shortList=headA;
            longList=headB;
        }
        while(gap--)
        {
            longList=longList->next;
        }
        while(longList!=shortList)
        {
            longList=longList->next;
            shortList=shortList->next;
        }
        return longList;
    }

9.环形链表1

输入图片说明

思路:设置快慢指针
bool hasCycle(struct ListNode *head) {
    struct ListNode* fast=head;
    struct ListNode* slow=head;
   while(fast&&fast->next)
   {
       fast=fast->next->next;
       slow=slow->next;
       if(slow==fast)
       return true;
   }
   return false;
       
}

10.环形链表2

思路1:见图

输入图片说明
利用公式推导出结论:

meetNode到入环点的距离 +(n-1)圈环周长 =head到入环点的距离
代码实现
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode*slow=head,*fast=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)
        {
            struct ListNode* meetNode=slow;
            while(meetNode!=head)
            {
                meetNode=meetNode->next;
                head=head->next;
            }
            return meetNode;
        }
        
    }
    return NULL;
}
思路二:将meetNode的节点 看成一个链表的起始点和尾节点的交点

输入图片说明

11.赋值带随机指针的链表

输入图片说明

思路:这道题最难的地方在于怎么得到每个指针的random
1.将copy节点复制其元素,插入到每个节点的next位置
2.将random定位到每一个指定元素的next位置就可以解决了
3.将新链表和原链表分离
代码如下:
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节点
        copy->next=cur->next;
        cur->next=copy;
        cur=copy->next;
    }
    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=NULL,*copyTail=NULL;
    cur=head;
    while(cur)
    {
        struct Node*copy=cur->next;
//为什么要多次设置copy=cur->next;
        struct Node*next=copy->next;
        if(copyTail==NULL)
        {
            copyHead=copyTail=copy;
        }
        else
        {
            copyTail->next=copy;
            copyTail=copy;
        }
        cur->next=next;
        cur=next;
    }
    return copyHead;	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值