代码随想录第四天 链表(02)

一、LeetCode24 两两交换链表中的节点

力扣

两两交换链表中的节点。给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

代码随想录 (programmercarl.com)

两两交换,最后一个节点如果没人了可以不交换的(原来是这样)

其实这是一个模拟题,推荐使用虚拟头结点方式进行,因为你必须知道这个节点的前一个节点。

自己写一遍其实能发现问题了:统一用dummyhead操作,不然容易晕!

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
       ListNode*dummy_head=new ListNode(0);
       dummy_head->next=head;
       ListNode*cur=dummy_head;
      while(cur->next!=NULL&&cur->next->next!=NULL){//这一步不能写反哦,不然空指针异常了
           ListNode*temp=cur->next;
           ListNode*temp1=cur->next->next->next;
           cur->next=cur->next->next;
           cur->next->next=temp;
           temp->next=temp1;
           cur=cur->next->next;
      }
       return dummy_head->next;
    }
};

链表指针指向题还是画图好理解,看不懂了就自己画个图。

二、LeetCode19删除链表倒数第N个节点。

力扣

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

进阶:你能尝试使用一趟扫描实现吗?

代码随想录 (programmercarl.com)

双指针典中典!fast先走n步,然后fast和slow同时移动,fast走到末尾,删除slow对应指针。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
     ListNode*dummy_head=new ListNode(0);
     dummy_head->next=head;
     ListNode*fast=dummy_head;
     ListNode*slow=dummy_head;
     while(n--&&fast!=NULL){
         fast=fast->next;
     }
     fast=fast->next;
     while(fast!=NULL){
         fast=fast->next;
         slow=slow->next;
     }
     slow->next=slow->next->next;
     return dummy_head->next;
    }
};

一遍过,轻轻松松拿下!只是需要注意,fast指针先走n+1步,然后二者同时移动,因为删除操作要操作上一个指针嘛!

当然C++删除元素的逻辑,还是要靠delete。

三、LeetCode142环形链表

力扣

题意: 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

说明:不允许修改给定的链表。

代码随想录 (programmercarl.com)

    判断有环:双指针法真的好用!fast指针一次走两步,slow指针一次走一步,fast指针先进入环,其后fast和slow相互追赶,二者相对速度为1,在环中肯定能相遇。遇上了就说明有环。

    如何找到环的入口?

    这里面的数学逻辑就深奥了,图片我不放出来,可以看上面连接的代码随想录,卡哥的动画还是很直观的。

   fast指针路程:x+y+n(y+z);   slow指针路程:x+y;(为什么slow指针不是好几圈详看代码随想录)

   二者速度差二倍关系,所以有:x+y+n(y+z)=2(x+y);

   所以x=ny+nz-y=(n-1)y+nz=(n-1)(y+z)+z;

   当n=1时,公式化简为x=z;也就是fast指针走了一圈就遇到了slow。

  所以我们在相遇点再定义一个指针,头节点定义一个指针,二者同时移动,每次一个单位,相遇    点就是环的入口。

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;
    }
};

四、LeetCode160链表相交

力扣

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

 代码随想录 (programmercarl.com)

异曲同工!和删除倒数第n个节点异曲同工之妙!双指针已经写了不少题了,到时候总结一下。

相交节点不是值相同,而是指针相同。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        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;
    }
};

目前看来是一道注水的模拟题....不过话说回来卡哥的函数名字真的好长啊。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值