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

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

力扣24

题目链接. - 力扣(LeetCode)

创建一个虚拟头结点dummyNode指向头结点,设置三个指针cur、left、right如下图所示:

首先令left.next = right.next

然后令cur.next = right

最后令right.next = left完成交换

随后调整三个指针的指向,cur = left、left = left.next、right = left.next,交换下两个节点位置

时间复杂度:O(n)

空间复杂度:O(1)

class Solution {
    public ListNode swapPairs(ListNode head) {

        //如果是只有头结点,则返回头结点
        if(head == null || head.next == null){
            return head;
        }

        ListNode dummyNode = new ListNode(0);
        dummyNode.next = head;

        ListNode cur = dummyNode;
        ListNode left = head;
        ListNode right = left.next;

        //当链表长度为2或者3时
        if(right.next == null || right.next.next == null){
            left.next = right.next;
            cur.next = right;
            right.next = left;
            right = right.next;
            left = cur.next;
        }

        while(right.next != null && right.next.next != null){
            left.next = right.next;
            cur.next = right;
            right.next = left;
            cur = left;
            left = left.next;
            right = left.next;
            if(right.next == null || right.next.next == null){
                left.next = right.next;
                cur.next = right;
                right.next = left;
                right = right.next;
                left = cur.next;
            }
        }

        return dummyNode.next;
    }
}

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

力扣19

题目链接. - 力扣(LeetCode)

设置两个指针left和right,二者初始时都指向头结点。让right向右移动n+1个身位,然后让right和left同时移动,直到right为空,此时left所指节点的下一个结点即为要删除的节点。

时间复杂度:O(n)

空间复杂度:O(1)

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummyNode = new ListNode(0);
        dummyNode.next = head;

        ListNode right = dummyNode;
        ListNode left = dummyNode;

        //right指针比left快n+1个身位,这样当right = null时,left.next即为要删除的节点
        for(int i = 0; i <= n; i++){
            right = right.next;
        }

        while(right != null){
            right = right.next;
            left = left.next;
        }

        left.next = left.next.next;

        return dummyNode.next;

    }
}

三、链表相交

面试题02.07

题目链接. - 力扣(LeetCode)

设置两个指针curA和curB分别指向headA和headB。

首先遍历得到两个链表A和B的长度sizeA和sizeB。随后计算两个链表长度差值step,然后更长的那个链表的cur指针向右移step个单位,这样curA和curB指向的部分在长度上就对齐了。

随后同时遍历A和B剩余的部分,当curA=curB时,说明此节点为相交结点

时间复杂度:O(n)

空间复杂度:O(1)

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode curA = headA;
        ListNode curB = headB;
        int sizeA = 0;
        int sizeB = 0;

        //求链表A和B的长度
        while(curA != null){
            sizeA++;
            curA = curA.next;
        }

        while(curB != null){
            sizeB++;
            curB = curB.next;
        }

        curA = headA;
        curB = headB;

        //计算两个链表长度差值step,然后更长的那个链表的指针右移step,这样curA和curB在长度上就对齐了。
        int step;
        if(sizeA >= sizeB){
            step = sizeA - sizeB;
            for(int i = 0; i < step; i++){
                curA = curA.next;
            }
            while(curA != null){
                if(curA == curB){
                    return curA;
                }
                curA = curA.next;
                curB = curB.next;
            }
        }else{
            step = sizeB - sizeA;
            for(int i = 0; i < step; i++){
                curB = curB.next;
            }
            while(curB != null){
                if(curB == curA){
                    return curB;
                }
                curB = curB.next;
                curA = curA.next;
            }
        }
        return null;
    }
}

四、环形链表II

力扣142

题目链接. - 力扣(LeetCode)

判断链表是否有环

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

找到环的入口

假设从头结点到环形入口节点的节点数为x。 环形入口节点到fast指针与slow指针相遇节点的节点数为y。 从相遇节点再到环形入口节点的节点数为 z。

那么在相遇时slow指针走过的节点数为x+y,fast指针走过的节点数x+y+n(y+z),n为fast指针在环内走了n圈才遇到slow指针,(y+z)为 一圈内节点的个数。因为fast走两步slow才走一步,则fast走过的节点数目是slow的两倍。因此(x+y)*2=x+y+n(y+z),由此可得x = (n-1)(y+z)+z。

这意味着slow再从头结点出发走到入环结点的时候,fast结点从在环内之前与slow相交的位置出发也走到了入环节点。因此可以令indexA = head,indexB = fast,令二者右移,indexA和indexB相交的位置即为入环节点。

时间复杂度:O(n)

空间复杂度:O(1)

public class Solution {
    public ListNode detectCycle(ListNode head) {
        //快慢指针法判断是否有环
        ListNode fast = head;
        ListNode slow = head;

        while(fast != null && fast.next != null){
            //fast走两步,slow走一步,如果有环fast肯定比slow先进环。
            fast = fast.next.next;
            slow = slow.next;
            //当fast和slow相遇的时候,说明有环
            if(fast == slow){
                ListNode index1 = fast;
                ListNode index2 = head;
                while(index1 != index2){
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }

        return null;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值