代码随想录2刷|链表1.链表理论基础2移除链表元素3.设计链表4.翻转链表5.两两交换链表中的节点6.删除链表的倒数第N个节点7.链表相交8.环形链表lI

本文介绍了几种常见的链表操作,包括移除链表元素的两种方法,设计链表的结构和操作,以及反转链表和两两交换链表节点的算法。此外,还讨论了删除链表倒数第N个节点的问题和寻找链表相交点的方法,特别提到了环形链表的检测和处理策略。

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

2移除链表元素

链接:力扣

 一刷:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
 /*
 和安迪一样挖地道吧,尽头是希望和自由啊
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode *L=new ListNode(-1);
        L->next=head;

        ListNode *slow=L,*fast=head,*r=L;

        while(fast!=nullptr)
        {
            if(fast->val==val)
            {
                slow->next=fast->next;
                fast=slow->next;
            }
            else{
                fast=fast->next;
                slow=slow->next;
            }
        }
        return L->next;



    }
};

跟一刷写法不太一样,一开始忘记slow->next=nullptr报错

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode *L=new ListNode(-1);
        L->next=head;
        ListNode *slow=L,*fast=L->next;
        if(head==nullptr)
        {
            return head;
        }
        while(fast!=nullptr)
        {
            if(fast->val==val)
            {
                fast=fast->next;
            }
            else
            {
                slow->next=fast;
                slow=slow->next;
                fast=fast->next;

            }
        }
        slow->next=nullptr;
        return L->next;

    }
};

707. 设计链表 

链接:力扣

 

二刷感觉比一刷理解的更深刻了。

期间用了尾指针,但是发现hold不住。只能尾插时从头开始找到尾再插入。

另外其实一些函数有出错,所以另外写了print函数,每一步都打印链表进行调试。

巧用了while(p!=nullptr && index) ,每次想着index=0,index=1进行写

class MyLinkedList {
public:
struct ListNode{
    int val;
    ListNode *next=nullptr;
    ListNode(int val):val(val),next(nullptr){};

};

    MyLinkedList() {//构造函数,初始化头节点
     //初始化头节点
        L=new ListNode(-1);
       // r=L;//尾指针

    }

    void print_L(ListNode *L)
    {
        ListNode *p=L->next;
        while(p!=nullptr)
        {
            cout<<p->val<<"  ";
            p=p->next;
        }
        cout<<endl;
    }
    
    int get(int index) {
        ListNode *p=L->next;
        while(p!=nullptr && index)
        {
            p=p->next;
            index--;
        }
        if(p!=nullptr)
        {
            return p->val;
        }
       // print_L(L);
        return -1;

    }
    
    void addAtHead(int val) {//头插法
        ListNode *temp=new ListNode(val);
        temp->next=L->next;
        L->next=temp;
       // print_L(L);
    }
    
    void addAtTail(int val) {//尾插法
        ListNode *temp=new ListNode(val);
        ListNode *r=L;
        while(r->next!=nullptr)
        {
            r=r->next;
        }
        r->next=temp;
        //print_L(L);
    }
    
    void addAtIndex(int index, int val) {
        //假设index=0,=1
        ListNode *p=L;
        ListNode *temp=new ListNode(val);
        //将一个值为 val 的节点插入到链表中下标为 index 的节点之前
        while(p!=nullptr && index)
        {
            p=p->next;
            index--;
        }
        if(p!=nullptr)//如果 index 比长度更大,该节点将 不会插入 到链表中
        {
            temp->next=p->next;
            p->next=temp;
        }
        //print_L(L);
        
    }
    
    void deleteAtIndex(int index) {
        //如果要删除节点,首先节点要存在
        ListNode *pre=L;
        while(pre!=nullptr && index)
        {
            pre=pre->next;
            index--;
        }
        if(pre==nullptr)
        {
            //没有什么好删的
        }
        else if(pre!=nullptr && pre->next==nullptr)
        {
            //没有什么好删的
        }
        else
        {
            pre->next=pre->next->next;
        }
       // print_L(L);

    }
    private:
        ListNode *L=nullptr;//L为头节点
       // ListNode *r=nullptr; 不太好掌握,废了



};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList* obj = new MyLinkedList();
 * int param_1 = obj->get(index);
 * obj->addAtHead(val);
 * obj->addAtTail(val);
 * obj->addAtIndex(index,val);
 * obj->deleteAtIndex(index);
 */

206.反转链表 

链接:力扣

  二刷还是各种报错,最主要的是忘记了一刷的简便算法

二刷的错误点在于边界判断太多了,而且一开始的慢指针尾巴忘记指向空指针,导致整个链表没有尾巴,一直报错了十分钟。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head==nullptr || head->next==nullptr)
        {
            return head;
        }

        ListNode *slow=head;
        //忘记写slow->next==nullptr,导致反转后的链表没有尾巴
        ListNode *fast=head->next;
         slow->next=nullptr;
        while(fast!=nullptr && fast->next!=nullptr)
        {
            ListNode *temp=fast;
            fast=fast->next;
            temp->next=slow;
            slow=temp;
        }
        if(fast!=nullptr)
        {
            fast->next=slow;
            return fast;
        }
        return  head;
        
    }
};

回忆一刷的简单做法,直接让slow指针从空开始,fast从head开始.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head==nullptr)
        {
            return nullptr;
        }
        ListNode *slow=nullptr,*fast=head;
        while(fast!=nullptr)
        {
            ListNode *temp=fast;
            fast=fast->next;
            temp->next=slow;
            slow=temp;
        }
        return slow;


    }
};

24. 两两交换链表中的节点 

链接:力扣

 基本还是搞错了,cur 和 temp temp1 三个指针 四个节点,相隔距离,链接关系,都是需要稍微死记硬背一点的。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    /*再看一遍我也只是跟着过一遍。
   重点 cur temp temp1 三个指针交叉成一个均匀的麻花,涉及四个节点,三个指针分别指向1、2、4节点
   
   最后cur=temp,每次前进一步

   */

public:
    ListNode* swapPairs(ListNode* head) {
        if(head==nullptr || head->next==nullptr)//只有0个或者1个节点
        {
            return head;
        }
        //两个及以上节点,可以交换
        ListNode *L=new ListNode(-1);
        L->next=head;
        ListNode *cur=L,*temp=nullptr,*temp1=nullptr;
        while(cur!=nullptr && cur->next!=nullptr && cur->next->next!=nullptr)
        {
            temp=cur->next;
            temp1=cur->next->next->next;

            cur->next=temp->next;
            cur->next->next=temp;
            temp->next=temp1;

            cur=temp;//每次只前进一步!!这里一开始写成了temp1
        }
        return L->next;
        


    }
};

 19. 删除链表的倒数第 N 个结点

链接:力扣

 十分尴尬,我已经忘了最佳的那种做法。。。。就是快慢指针那种。

对链表遍历了两遍。

二刷做法:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        //以第一个为例,删除倒数第2个节点,就是找倒数第三个节点==正数第三个节点,链表长度为5.意思是找到第len-n个节点即可

        //第一步,创建头节点
        ListNode *L=new ListNode(-1);
        L->next=head;

        //第二步,计算整个链表长度
        ListNode *p=L->next;
        int len=0;
        while(p!=nullptr)
        {
            len++;
            p=p->next;
        }
       
        int k=len-n;
        p=L;//这一步很重要!一定要搞清楚!!
        while(p!=nullptr && k)
        {
            p=p->next;
            k--;
        }
        if(p!=nullptr && p->next!=nullptr)
        {
            p->next=p->next->next;
        }
        return L->next;

    }
};

一刷,快慢指针最佳做法,重新写一遍.注意n++。fast和slow都从空的头节点开始,fast要先走n+1步

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    /*
    以第一个为例,删除链表的倒数第2个节点相当于找到正数第三个节点
                               3                    2
                               n                    len-n
    让fast指针先走n步,然后slow再和fast一起走
    */
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        if(head==nullptr )
        {
            return head;
        }
        ListNode *L=new ListNode(-1);
        L->next=head;
        ListNode *fast=L,*slow=L;
        n++;
        while(n && fast!=nullptr)
        {
             fast=fast->next;
             n--;
        }
        
       

        while(fast!=nullptr)
        {
            slow=slow->next;
            fast=fast->next;
        }
         
        if(slow!=nullptr && slow->next!=nullptr)
        {
            slow->next=slow->next->next;
        }
        return L->next;

    }
};

面试题 02.07. 链表相交 

链接:力扣

 挺好的,看了以前写的那一遍,然后重写了一遍。只能说对于资质普通者,要重复刷题才行。

p1 、p2第一次遍历完后要从恢复到链表头开始遍历

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *p1=headA,*p2=headB;
        int lenA=0,lenB=0;
        while(p1!=nullptr)
        {
            p1=p1->next;
            lenA++;
        }

         while(p2!=nullptr)
        {
            p2=p2->next;
            lenB++;
        }
        int len=lenA-lenB;
        // cout<<lenA<<"    "<<lenB<<"  "<<len<<endl;

        //重新从头开始遍历
        p1=headA,p2=headB;
        if(lenA>=lenB)
        {
            while(len && p1!=nullptr)
            {
                p1=p1->next;
               // cout<<"p1    "<<p1->val<<endl;
                len--;
            }

        }
        else
        {
            len=-len;
             while(len && p2!=nullptr)
            {
                p2=p2->next;
                len--;
            }
        }
        while(p1!=nullptr && p2!=nullptr && p1!=p2)
            {
                p1=p1->next;
                p2=p2->next;
            }
            return p2;
        
        
    }
};

142. 环形链表 II

链接:力扣

 二刷发现思路记错了,fast一次走两步,slow一次走一步,我记成fast多走两步后,两个就同步了。确实如果fast只是先多走两步,那毫无意义,fast和slow永远差两步永远不会相交!!

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
 /*
 有一道题印象深刻,判断两个链表相交的位置。突然发现是这道题!真尴尬
 基本思路:
 先让fast节点多走两步,!!fast指针是一步走两个节点,slow指针一步走一个节点
 然后fast和slow必然在环内相交。记住环内相交节点,然后让第三个指针从链表起始节点出发,相交节点指针和起始指针同步出发,来到环的入口节点
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head==nullptr || head->next==nullptr)
        {
            return nullptr;
        }
        ListNode *fast=head,*slow=head;
        while(fast!=nullptr && fast->next!=nullptr)
        { 
            slow=slow->next;
            fast=fast->next->next;
            if(slow==fast)//说明有环
            {
               //cout<<"有环"<<endl;
                ListNode *p=head;
                while(p!=slow)
                {
                    p=p->next;
                    slow=slow->next;
                }
                return slow;

            }
        }
        return nullptr;
        
        
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值