代码随想录训练营第四天(链表2)

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

思路

建议使用虚拟头结点,这样会方便很多,要不然每次针对头结点(没有前一个指针指向头结点),还要单独处理。

接下来就是交换相邻两个元素了,此时一定要画图,不画图,操作多个指针很容易乱,而且要操作的先后顺序

个人思路:

画图一步步模拟

交换1节点和2节点:

创建虚拟头节点(ListNode* V_head =new ListNode(0);

V_head->next = head;)

设置当前节点指向虚拟头节点(ListNode* cur =V_head;)

当 当前节点的下一节点及下下节点不为空则继续循环(头节点设为0节点)

保存1节点(ListNode* tmp =cur->next;)

保存3节点(ListNode* tmp1 = cur->next->next->next;)

节点0指向节点2(cur->next = cur->next->next;)

节点2指向节点1( cur->next->next =tmp;)

节点1指向节点3(tmp->next = tmp1;)

交换完成 cur向前移动2位(cur = cur->next->next;)

返回头节点(return V_head->next;)

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
      ListNode* V_head =new ListNode(0);//设置一个虚拟头节点
      V_head->next = head;
      ListNode* cur =V_head;
      while(cur->next !=nullptr && cur->next->next !=nullptr){
        //这里交换节点1和节点2
        ListNode* tmp =cur->next;//保存第一个节点
        ListNode* tmp1 = cur->next->next->next; //保存第三个节点
        cur->next = cur->next->next;//头节点指向节点2
        cur->next->next =tmp;//节点2指向节点1
        tmp->next = tmp1;//节点1指向节点3
        //往后移动链表(cur移动两位)
        cur = cur->next->next;
      }
      //返回头节点
      return V_head->next;
    }
};

2024.5.14 二刷

代码思路

交换两两相邻的元素

设置一个虚拟头节点 设置当前节点指针(ListNode* V_head =new ListNode(0);//设置一 个虚拟头节点 V_head->next = head; ListNode* cur =V_head;)

当当前节点的下一节点及下下节点不为空(要交换的两个节点不为空)(while(cur->next !=nullptr && cur->next->next !=nullptr))

首先保存第一个节点与第三个节点(ListNode* tmp =cur->next;//保存第一个节点 ListNode* tmp1 = cur->next->next->next; //保存第三个节点)

交换节点(cur->next = cur->next->next;//头节点指向节点2 cur->next->next =tmp;//节点2指向节点1 tmp->next = tmp1;//节点1指向节点3)

交换完往下移动2步 交换下一相邻节点(cur = cur->next->next;)

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

思路

双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。

  • 定义fast指针和slow指针,初始值为虚拟头结点,如图:

    img

fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:

img

fast和slow同时移动,直到fast指向末尾,如题:

img

删除slow指向的下一个节点,如图:

img

快慢指针

快慢指针永远相差n 当快指针移动到最后 为空时 慢指针就指向倒数第n个节点

创建虚拟头节点(ListNode* V_head =new ListNode(0);//虚拟头节点

V_head->next = head;)

创建快慢指针

注意治理走到最后 fast跟slow相差n  所以当fast走到末尾时指向空指针,此时slow对应的就是倒数的第n个数了

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
    ListNode* V_head =new ListNode(0);//虚拟头节点
    V_head->next = head;
    //快慢指针
    ListNode* fast =V_head;
    ListNode* slow =V_head;
    //先让fast 走n+1步找到第n个节点 (如果n大于链表长度 则fast为空)
    while(n-- && fast!= NULL){
       fast = fast->next;
    }
    fast =fast->next;//n+1步
    //当fast走到第n+1,开始移动slow到n个节点的上一个节点;
    while(fast!=NULL){
     fast = fast->next;
     slow =slow->next;
    }
    slow->next =slow->next->next;//删除节点
    return V_head->next;
    }

};

160. 相交链表

思路(o(n+m))

简单来说,就是求两个链表交点节点的指针。 这里同学们要注意,交点不是数值相等,而是指针相等。

为了方便举例,假设节点元素数值相等,则节点指针相等。

看如下两个链表,目前curA指向链表A的头结点,curB指向链表B的头结点:

面试题02.07.链表相交_1

我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置,如图:

面试题02.07.链表相交_2

此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。

否则循环退出返回空指针。

ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0, lenB = 0;
        while (curA != NULL) { // 求链表A的长度
            lenA++;
            curA = curA->next;
        }
        while (curB != NULL) { // 求链表B的长度
            lenB++;
            curB = curB->next;
        }
        curA = headA;
        curB = headB;
        // 让curA为最长链表的头,lenA为其长度
        if (lenB > lenA) {
            swap (lenA, lenB);
            swap (curA, curB);
        }
        // 求长度差
        int gap = lenA - lenB;
        // 让curA和curB在同一起点上(末尾位置对齐)
        while (gap--) {
            curA = curA->next;
        }
        // 遍历curA 和 curB,遇到相同则直接返回
        while (curA != NULL) {
            if (curA == curB) {
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return NULL;

142. 环形链表 II

思路

判断链表是否有环

可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。

要注意 在进入环后只会继续在环里面转圈圈,此时fast 相对于 slow  是做步进为1的靠近,一个不动(slow),一个以1的速度向前步进(fast) 这样子总会相遇的

龟兔赛跑

1.设置快慢指针指向头节点()

ListNode* fast = head;
        ListNode* slow = head;

2.当快指针及快指针节点的下一节点不为空进入循环(while(fast != NULL && fast->next != NULL)

快指针走两步慢指针走一步()

slow = slow->next;
            fast = fast->next->next;

3.当快指针与慢指针相遇,设置初始指针及相遇点指针

f (slow == fast) {
                ListNode* index1 = fast;
                ListNode* index2 = head;

4.两个指针同时向前移动,移动到相遇位置即为入口

 while (index1 != index2) {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index2; // 返回环的入口
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast != NULL && fast->next != NULL) {
            slow = slow->next;
            fast = fast->next->next;
            // 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
            if (slow == fast) {
                ListNode* index1 = fast;
                ListNode* index2 = head;
                while (index1 != index2) {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index2; // 返回环的入口
            }
        }
        return NULL;
    }
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值