day04 |两两交换链表中的节点、删除链表的倒数第N个节点、链表相交、环形链表II

目录

两两交换链表中的节点

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

链表相交

环形链表||


两两交换链表中的节点

题目链接:24. 两两交换链表中的节点

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

思路:首先需要定义一个虚拟指针dummy,方便后续输出头节点;

然后定义一个cur指针:指向要进行交换操作的两个结点的前面一个结点;

之后对其进行以下三步操作即可

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummy = new ListNode(-1,head);
        ListNode cur = dummy;
        //定义三个临时节点,方便后续交换操作
        ListNode node1,node2,node3;
        //当下一轮进行交换的结点不足两个时,跳出循环,直接输出就行了
        while(cur.next != null && cur.next.next != null){
            node1 = cur.next;
            node2 = cur.next.next;
            node3 = node2.next;

            //两两交换操作
            cur.next = node2;
            node2.next = node1;
            node1.next = node3;

            //更新cur指针
            cur = node1;
        }
        return dummy.next;
    }
}

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

题目链接:19. 删除链表的倒数第 N 个结点

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

思路:用到快慢指针,同时因为头结点也有可能被删除,需要定义虚拟指针方便输出最后结果。

slow指针:获指向被删节点的前一个节点

fast指针:用于遍历链表,直至fast.next为空

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(-1,head);
        ListNode slow = dummy,fast = dummy;
        while(n-- > 0){
            fast = fast.next;
        }
        //题中n的值小于等于结点数量,所以fast不可能是空节点
        while(fast.next != null){
            fast = fast.next;
            slow = slow.next;
        }
        //此时slow节点就是被删节点的前一个节点,slow.next结点不可能在fast后边,所以slow.next也不可能是空节点
        slow.next = slow.next.next;

        return dummy.next;
    }
}

链表相交

题目链接:链表相交

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

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

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

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

思路:采用合并链表的思想,定义p1,p2两指针

p1:遍历headA,为空时则遍历headB,实现"合并链表"

p2:遍历headB,为空时则遍历headA,实现"合并链表"

退出循环后,p1、p2遍历过的结点为:

 p1:a1、a2、c1、c2、c3、b1、b2、b3、c1

p2:b1、b2、b3、c1、c2、c3、a1、a2、c1

p1和p2两者必定相遇在第二个“c1”,实现"链表合并"

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //合并链表,实现同步移动
        ListNode p1 = headA,p2 = headB;
        while(p1 != p2){
            //p1 走一步,如果走到 A 链表末尾,转到 B 链表
            if(p1 == null)p1 = headB;
            else          p1 = p1.next;
            // p2 走一步,如果走到 B 链表末尾,转到 A 链表
            if(p2 == null)p2 = headA;
            else          p2 = p2.next;
        }
        //如果继续遍历原链表,就相当于追及问题了,也能ac,但耗时太长!!

        return p1;
    }
}

环形链表||

题目链接:142. 环形链表 II

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

思路:用到快慢指针,在两者相交之前,fast指针一次两步,slow指针一次一步。

待相遇之时,快指针所走路程是满指针所走路程的两倍

满足:x + quan1*(z+y) + y= 2*x + 2*quan2*(z+y) + 2 * y,  化简得z = x + (2*quan2-quan1+1)*(z+y)

需要注意:max(2*quan2-quan1) = 0,   此时头结点就是相交点,x = 0,y = 0;

当2*quan2-quan1为负数时,z <= x,  此时 路程x 是 路程z + 圈数的路程(可以为0) ;

所以之后fast从相遇点出发,slow从head出发时,slow是不可能进入环内的,slow与fast一旦相等,那就是链表开始入环的第一个节点!!

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head == null)return null;
        ListNode fast = head,slow = head;

        while(fast.next != null && fast.next.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow)break;
        }
        //没有环,直接返回null
        if(fast.next == null || fast.next.next == null)return null;

        //此时fast与slow相交,slow从head出发,fast从相交点出发
        slow = head;
        while(slow != fast){
            slow = slow.next;
            fast = fast.next;
        }

        return fast;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值