代码随想录算法训练营第四天| 24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点 、 160.链表相交、142.环形链表II

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

题目链接:

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

思路:

加上头结点后从头往后做,注意别断链。

做题过程:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
//建立虚拟头结点
        ListNode *vir_head=new ListNode(0,head);
//cur指向交换的第一个节点,temp用来辅助不断链,pre记录cur之前的节点
        ListNode* cur=vir_head->next,* temp,*pre=vir_head;
//如果交换的两个节点都非空
        while(cur!=NULL&&cur->next!=NULL){
//保存后面的链接
            temp=cur->next->next;
//将前面的元素与交换后的节点相连
            pre->next=cur->next;
//相邻节点next方向转向
            cur->next->next=cur;
            cur->next=temp;
//移动cur和pre,准备下一次交换
            pre=cur;
            cur=temp;
        }
//保存头部指针,删除虚拟头结点
        head=vir_head->next;
        delete vir_head;
        return head;
    }
};

总结:

这题还是得画图,不然指针绕来绕去真的会弄不清楚。

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

题目链接:

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

思路:

用两个相距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) {
        ListNode* dummyHead=new ListNode(-1,head);
        ListNode* fast=dummyHead,*slow=dummyHead;
//因为题目说了n的取值范围,所以默认n都是有效值了
        while(n--){
            fast=fast->next;
        }
//快慢指针一起移动
        while(fast->next){
            fast=fast->next;
            slow=slow->next;
        }
//删除操作
        ListNode *temp=slow->next;
        slow->next=slow->next->next;
        delete temp;
        head=dummyHead->next;
        delete dummyHead;
        return head;
    }
};

总结:

和代码随想录给的题解有点区别,考虑了一下应该是因为我判断的是fast->next是否存在,因为fast指针不用额外移动一次了。

面试题02.07.链表相交

题目链接:

面试题 02.07. 链表相交

思路:

让两个链表先尾部对齐,然后从对齐的位置开始往后查找,如果相同就返回该点,否则两个指针一起后移。

做题过程:

一直提醒我在处理长链表的时候越界了,没头绪的在下面找了很久,结果发现原来是计算长度的时候把头指针给移动了,啊!

/**
 * 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) {
        //求长度
        int lengthA=0,lengthB=0,gap=0;
        ListNode *curA=headA,*curB=headB;
        while(headA!=NULL){
            lengthA++;
            headA=headA->next;
        }
        while(headB!=NULL){
            lengthB++;
            headB=headB->next;
        }
        //对更长的链表的指针做移动
        curA=headA;
        curB=headB;
        if(lengthAnext;
            }
        }else{
            gap=lengthB-lengthA;
            while (gap--) {
            curA = curA->next;
            }
        }
        while(curA!=NULL&&curB!=NULL){
            //判断指针是否相同而不是值是否相同
            if(curA->val==curB->val){
                return curA;
            }
            curA=curA->next;
            curB=curB->next;
        }
        return NULL;
    }
};

调整好了顺利通过。

/**
 * 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) {
        //求长度,gap用来指示长的链表需要头指针后移几个单位再开始比较
        int lengthA=0,lengthB=0,gap=0;
        //千万记得别动头指针
        ListNode *curA=headA,*curB=headB;
        while(curA!=NULL){
            lengthA++;
            curA=curA->next;
        }
        while(curB!=NULL){
            lengthB++;
            curB=curB->next;
        }
        //对更长的链表的指针做移动
        curA=headA;
        curB=headB;
        if(lengthA>lengthB){
            gap=lengthA-lengthB;
            while(gap--){
                cout<val<<" ";
                curA=curA->next;
            }
        }else{
            gap=lengthB-lengthA;
            while(gap--){
                cout<val<<" ";
                curB=curB->next;
            }
        }
        while(curA!=NULL&&curB!=NULL){
            //判断指针是否相同,而不是值是否相同
            if(curA==curB){
                return curA;
            }
            curA=curA->next;
            curB=curB->next;
        }
        //没找到返回NULL
        return NULL;
    }
};

总结:

①千万记得下次遍历链表的时候不能动头指针。

②注意题目中的相交指的是链表有同样的结点,也就是指针相同,而不是值相同。

③代码随想录中的长链表判断和处理更符合程序思维,简化为始终处理A链表,如果B更长就将B和A交换,还是看做对A做处理。

142.环形链表II  

题目链接:

142.环形链表II

思路:

没有思路,看看代码随想录的讲解。把环形链表讲清楚! 如何判断环形链表?如何找到环形链表的入口?

所以这题要解决两个问题,一是判断是否有环,二是判断如何找到环的出口,具体的思路视频里比较清晰我就不赘述了。

做题过程:

找准思路了顺利提交通过。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *fast=head,*slow=head;
        int tag=0;//是否存在环路
        while(fast!=NULL&&fast->next!=NULL){//fast指针一次走两步
            fast=fast->next->next;
            slow=slow->next;//slow指针一次走一步
            if(fast==slow){//如果相遇说明存在环
                tag=1;//有环路标志位记作1
                break;//跳出循环
            }
        }
        if(tag==0){//如果没有改变标志位说明不存在环路
            return NULL;
        }
        slow=head;//slow指针从头开始
        while(slow!=fast){//fast现在位于两者相遇的位置
            slow=slow->next;
            fast=fast->next;
        }
        return slow;//fast和slow再次相遇的位置就是环的入口
    }
};

总结:

这题如果不了解,真的很难想到。

要掌握这题的数学逻辑,要搞明白为什么快慢指针相遇代表有环?为什么从相遇位置和头结点再次出发的两个指针相遇的位置就是环的入口?

你可能感兴趣的:(算法,链表,c++,leetcode)