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

24. 两两交换链表中的节点 - 力扣(LeetCode)

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

输入:head = [1,2,3,4]
输出:[2,1,4,3]

思考:1.两两交换步骤有三步;

2.下一个循环从哪里开始?上一步交换完了,应该是1节点的next指向4节点,所以下一步循环应该从1结点开始,cur从虚结点开始,往后移动了两次,指向1节点。

解法:需要两个记录指针,一是记录脱离新链表的起始节点(上图中的5节点),二是记录交换是脱离的节点(上图中的3节点);注意一下判断条件,cur->next不等于空,还有cur往后移动两次也不能为空(cur->next->next不为空)。

代码:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dhead=new ListNode(0);
        dhead->next=head;
        ListNode* cur=dhead;
        while(cur->next!=nullptr&&cur->next->next!=nullptr){
            ListNode* temp1=cur->next;//记录需要交换放在后面的节点
            ListNode* temp2=cur->next->next->next;//记录等待交换的开始节点
            cur->next=cur->next->next;
            cur->next->next=temp1;//接上交换放在后面的节点
            cur->next->next->next=temp2;//接上后面未处理的节点

            cur=cur->next->next;
        }

        return dhead->next;
    }
};

收获:整个交换下来,cur(开始处理指针位置)都没有变过,始终都是用->next和临时指针去处理,这有个好处,就是方便理解下一次循环从哪开始。

19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

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

示例 1:

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

思路:一开始思路就是把链表size求出来,再减去n,一个循环让指针移动size-n就可以了,但是学到新的方法,滑动窗口发现比原来快多了,我不需要计算链表有多长。

解决:利用滑动指针或者说左右指针,先从结果分析,最后左值针应该指向倒数n+1个节点上,右指针应该指向链表尾节点的下一个,right-left刚好等于n+1;

所以分两步:1.创建一个right-left=n+1的窗口;2.同时移动left和right指针,直到right=null。

代码:

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dhead = new ListNode(0);
         dhead->next = head;
        ListNode* left=dhead;
        ListNode* right=dhead;
        while(n--&&right!=NULL){
            right=right->next;
        }
        right=right->next;
        while(right!=NULL){
            right=right->next;
            left=left->next;
        }
        if(left->next!=NULL){
            left->next=left->next->next;
        }
        return dhead->next;
    }
};

收获:一开始没有用虚头节点,当n=1时,链表只有一个元素时候出错。

面试题 02.07. 链表相交 - 力扣(LeetCode)

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

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

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

思考:问题简单来看就是两个指针最后有没有指向同一个元素,如果指向就说明有交点,那就有一个前提,这两个指针必须同时移动并且同时开始位置要一致,这就引出下一个问题,如何使两个指针在同一位置开始移动?

解决:最好的办法就是从链表长度入手,n-m就是长链表需要移动的距离,短链表从头结点开始就可以。

代码:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int sizeA=0;
        int sizeB=0;
        ListNode* A=headA;
        ListNode* B=headB;
         
        while(A!=NULL){
            sizeA+=1;
            A=A->next;
        }
        while(B!=NULL){
            sizeB+=1;
            B=B->next;
        }
        A = headA;
        B = headB;
        if(sizeA>sizeB){
            int n=sizeA-sizeB;
            while(n--){
                A=A->next;
            }
        }
        else{
            int n=sizeB-sizeA;
            while(n--){
                B=B->next;
            }
        }
        while(A!=NULL&&B!=NULL){
            if(A==B){
                return A;
            }
                A=A->next;
                B=B->next;
        }
        return NULL;
    }
    
};

142. 环形链表 II - 力扣(LeetCode)

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

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

今天难题来了。。。

说实话一开始毫无头绪,先看代码随想录的讲解;自己再捋一遍过程。

两个问题:1.有没有环;2.环的起点在哪(难点)

思路:1.利用快慢指针的追击,快走两步,慢走一步,如果两个指针相遇说明有环;

           2.从头结点出发一个指针,从相遇节点也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。也就是在相遇节点处,定义一个指针index1,在头结点处定一个指针index2。让index1和index2同时移动,每次移动一个节点, 那么他们相遇的地方就是 环形入口的节点。(以上这些是推导出来的具体过程不重复,指路代码随想录 (programmercarl.com))。

解决:1.快慢指针开始跑,相遇记录为index2,说明有环,没有返回NULL;2.有环,index1从头节点开始,index1和index2都走一步,相遇的节点就是环的起点(入口)。

代码:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast=head;
        ListNode* slow=head;
        while(fast!=NULL&&fast->next!=NULL){
            fast=fast->next->next;
            slow=slow->next;
            if(fast==slow){
                ListNode* index1=head;
                ListNode* index2=fast;
                while(index1!=index2){
                    index1=index1->next;
                    index2=index2->next;
                }
                return index1;
            }
        }
        return NULL;
    }
};

收获:判断有环应该用快慢指针追击解决,试着解决一下这题141. 环形链表 - 力扣(LeetCode)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值