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

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

学习文档链接: 代码随想录

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

链接: 两两交换链表中的节点

该题思路:

在这里插入图片描述

自己初始想法【错误想法】:没有考虑使用dummyHead,导致在后面返回头节点的时候找不到头节点,可能是受到上个题目反转链表的影响(因为上个题在最后返回的指针pre是头指针,这个题目不使用虚拟头节点的话找不到最后的头节点),在考虑的时候认为不需要使用虚拟头节点,所以没有解出来。。。

代码如下:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* cur = dummyHead;
        while(cur->next!=nullptr &&cur->next->next!=nullptr){
            ListNode* tmp1 = cur->next;
            ListNode* tmp2 = cur->next->next->next;
            cur->next = cur->next->next; //不需要存cur->next->next,因为第一次指向的时候能找到cur->next->next。
            cur->next->next = tmp1;
            cur->next->next->next = tmp2;
            cur = cur->next->next;
        }
        ListNode* result = dummyHead->next;
        return result;
    }
};

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

链接: 删除链表的倒数第 N 个结点
思路:

由于无法直接从后面遍历链表,同时链表长度也未知,那么要在只遍历一遍链表的情况下实现该题,只能使用双指针slow和fast,先让fast前进n步,然后fast和slow同时前进,直到fast走到末端,此时slow所指向的元素正是倒数底n个节点。
由于删除链表操作需操作前一节点,所以直接使用虚拟头节点最方便。

代码如下:

/**
 *2024-05-13 想到了删除第k个(k=链表长度-n+1),但没有后续想法了
 **/
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* fast = dummyHead;
        ListNode* slow = dummyHead;
        while(n--){
            fast = fast->next;
        }
        while(fast->next){
            fast = fast->next;
            slow = slow->next;
        }
        ListNode* tmp = slow->next;
        slow->next = slow->next->next;
        delete tmp;
        ListNode* result = dummyHead->next;
        delete dummyHead;
        return result;
    }
};

三、面试题 02.07. 链表相交

链接: 链表相交
初始想法:

在看到此题目时,意识到可能需要使用"先走差距步"方法来遍历,但是错误得认为在两个链表的交点后面的链表可能分叉,其实是不可能分叉的,因为一旦指针相同之后,后续指针只能指向一个节点,所以相交后的链表节点一定是相等的。

代码如下:


/**2024-05-13
* 有一个关键点是:如果两个链表相交,那么从交点以后的链表一定是相同的,因为多个指针可以指向同一个节点,但一个指针不能指向多个节点,所以一旦有交点,那么交点后面的一定相同。
*基于上面的关键点,我们就可以通过两条链表末端对齐来找交点。
**/
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int sub = 0;
        int lenA = 0;
        int lenB = 0;
        while(curA){
            lenA++;
            curA = curA->next;
        }
        while(curB){
            lenB++;
            curB = curB->next;
        }
        curA = headA;
        curB = headB;
        if(lenA>lenB){
            sub = lenA-lenB;
            while(sub--){
                curA = curA->next;
            }
        }
        else{
            sub = lenB-lenA;
            while(sub--){
                curB = curB->next;
            }
        }
        while(curA!=nullptr&&curB!=nullptr){
            if(curA==curB){
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return nullptr;
    }

};

四、环形链表II

链接: 环形链表II
思路:

解决两个问题:
1、检测链表有无环:使用快慢指针,fast走两步,slow走一步,如果fast能赶上slow,那么一定是有环的,否则就没环。
2、有环如何找入环节点:经过公式推导发现,从头节点和fast与slow相遇的节点分别出发两个指针index1,index2,index1走到入环点时,index2一定也在入环点,无论index2在环内转了几圈。

代码如下:

/**
*2024-05-13
*两个问题:
*1、检测链表有无环:使用快慢指针,fast走两步,slow走一步,如果fast能赶上slow,那么一定是有环的,否则就没环。
*2、有环如何找入环节点:经过公式推导发现,从头节点和fast与slow相遇的节点分别出发两个指针index1,index2,index1走到入环点时,index2一定也在入环点,无论index2在环内转了几圈。
**/
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        ListNode* middle = nullptr;
        //检测是否有环
        while(fast&&fast->next){//我在此还加了fast->next->next,程序运行正常,但是随想录代码中并没有判断这个,具体不太清楚,可能原因是(因为fast->next->next=0时直接退出循环)。
            fast = fast->next->next;
            slow = slow->next;
            if(fast == slow){
                middle = fast;
                break;
            }
        }
        if(!middle){
            return nullptr;
        }
        //有环找入环节点
        ListNode* index1 = head;
        ListNode* index2 = fast;
        while(index1&&index2){
            if(index1 == index2){
                return index1;    
            }
            index1 = index1->next;
            index2 = index2->next;
        }
        return index1;

    }
};

总结

1、在操作链表时候,一定要注意哪些节点在重新连接之后就找不到了,要将其存起来用来继续遍历或者删除时用。 2、在链表操作中,”先走差距步“的遍历方法一定要掌握 3、判断链表是否有环通过快慢指针实现,快指针走两步,慢指针走一步,快能追上慢则一定存在环,否则不可能存在 4、判断入环口:分别从head和相遇点出发两个指针,直到两个相遇,那么该相遇点必是入环口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值