代码随想录算法训练营第四天| 19.删除倒数第K个节点、24.两两交换、142.环形链表2、160.判断链表是否相交

day-4

19.删除倒数第K个节点

在链表算法题中,加入虚拟头节点(dummy node)的主要目的是简化链表的操作。虚拟头节点是一个不存储实际数据的节点,它仅用于指向链表的第一个真正的节点。使用虚拟头节点可以避免对第一个真正节点进行特殊处理,从而使代码更加简洁。

例如,当我们需要在链表中删除一个特定节点时,我们需要找到该节点的前一个节点来修改其指针,但是如果该节点是链表的头节点,就需要特殊处理,这会导致代码逻辑复杂。而如果加入了虚拟头节点,那么遍历链表时就可以始终从虚拟头节点的下一个节点开始,从而避免了特殊处理头节点的问题。

此外,加入虚拟头节点还可以避免空链表(即链表中没有节点的情况)的特判处理。因为虚拟头节点的存在,头节点和其他节点都是按照同样的方式进行处理的,这简化了代码的编写和阅读。

https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
虚拟节点
删除倒数第K个,那么就要找到倒数第K+1个,然后K+1.next=k+1.next.nxet
就把第K个给删了
package com.example.leetcode.labuladong.sxl.sxl_4;

/**
 * 删除倒数第K个节点
 *
 * https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
 */
public class sxl_19 {
    class ListNode{
        int val;
        ListNode next;
        ListNode(){

        }
        ListNode(int val){
            this.val = val;
        }
        ListNode(int val,ListNode next){
            this.val = val;
            this.next = next;
        }
    }

    /**
     * 在链表算法题中,加入虚拟头节点(dummy node)的主要目的是简化链表的操作。
     * 虚拟头节点是一个不存储实际数据的节点,它仅用于指向链表的
     * 第一个真正的节点。使用虚拟头节点可以避免对第一个真正节点进行特殊处理,从而使代码更加简洁。
     *
     * 例如,当我们需要在链表中删除一个特定节点时,我们需要找到该节点的前一
     * 个节点来修改其指针,但是如果该节点是链表的头节点,就需要特殊处理,这会导
     * 致代码逻辑复杂。而如果加入了虚拟头节点,那么遍历链表时就可以始终从虚拟头节
     * 点的下一个节点开始,从而避免了特殊处理头节点的问题。
     *
     * 此外,加入虚拟头节点还可以避免空链表(即链表中没有节点的情况)的特判处理。
     * 因为虚拟头节点的存在,头节点和其他节点都是按照同样的方式进行处理的,这简化了代码的编写和阅读。
     *
     * 删除倒数第K,那么我们要找到到倒数第K+1个
     */
    public ListNode removeNthFromEnd(ListNode head, int n) {
        // 虚拟头结点
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        // 删除倒数第 n 个,要先找倒数第 n + 1 个节点
        ListNode x = findFromEnd(dummy, n + 1);
        // 删掉倒数第 n 个节点
        x.next = x.next.next;
        return dummy.next;
    }

    // 返回链表的倒数第 k 个节点
    ListNode findFromEnd(ListNode head, int k) {
        ListNode p1 = head;
        // p1 先走 k 步
        for (int i = 0; i < k; i++) {
            p1 = p1.next;
        }
        ListNode p2 = head;
        // p1 和 p2 同时走 n - k 步
        while (p1 != null) {
            p2 = p2.next;
            p1 = p1.next;
        }
        // p2 现在指向第 n - k 个节点
        return p2;
    }
}

24.两两交换

两两交换链表中的值

https://leetcode.cn/problems/swap-nodes-in-pairs/
1、先进性判断,当前链表是否满足两两交换的条件:条件就是至少有2个节点
2、满足的话,我们就先交换前面2个,然后后面的再走递归获取
package com.example.leetcode.labuladong.sxl.sxl_4;

/**
 * 两两交换
 * <p>
 * https://leetcode.cn/problems/swap-nodes-in-pairs/
 */
public class sxl_24 {
    class ListNode {
        int val;
        ListNode next;

        ListNode() {

        }

        ListNode(int val) {
            this.val = val;
        }

        ListNode(int val, ListNode next) {
            this.val = val;
            this.next = next;
        }

    }

    /**
     * 两两反转,直接按照顺序,前面两个反转完了,就再反转后面两个
     * 如此循环往复即可
     */
    public ListNode swapPairs(ListNode head) {
        // 首先先判断一下是否为null或者是否只有一个,这种情况下就不用再交换了
        if(head == null || head.next == null){
            return head;
        }

        /**
         * 先取出来第一个和第二个
         */
        ListNode first = head;
        ListNode second = head.next;
        ListNode others = head.next.next;

        /**
         * 第一和第二进行交换
         * 第一的next指向后面的递归
         */
        second.next = first;
        first.next = swapPairs(others);

        return second;
    }
}

142.环形链表2

/**
 * 判断是否是环形链表,以及如果是,判断一下起始节点
 */
快慢指针,快是2倍数走,慢是1倍数走,等到2者相遇,慢从头走,快1倍数走,再次相遇,就是环起始点
package com.example.leetcode.labuladong.sxl.sxl_4;

/**
 * 判断是否是环形链表,以及如果是,判断一下起始节点
 */
public class sxl_142 {
    class ListNode{
        int val;
        ListNode next;
        ListNode(){

        }
        ListNode(int val){
            this.val = val;
        }

        ListNode(int val,ListNode next){
            this.val = val;
            this.next = next;
        }
    }

    public ListNode detectCycle(ListNode head) {
        ListNode fast, slow;
        fast = slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) break;
        }
        // 上面的代码类似 hasCycle 函数
        if (fast == null || fast.next == null) {
            // fast 遇到空指针说明没有环
            return null;
        }

        // 重新指向头结点
        slow = head;
        // 快慢指针同步前进,相交点就是环起点
        while (slow != fast) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

160.判断链表是否相交

/**
 * 判断链表是否相交
 *
 * https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/
 */
个人很喜欢的一种写法,二者同时遍历,相等就退出(退出时要么都是null,要么就是相交的点)
package com.example.leetcode.labuladong.sxl.sxl_4;

/**
 * 判断链表是否相交
 *
 * https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/
 */
public class sxl_160 {
    class ListNode{
        int val;
        ListNode next;
        ListNode(){

        }

        ListNode(int val){
            this.val = val;
        }

        ListNode(int val,ListNode next){
            this.val = val;
            this.next = next;
        }
    }

    /**
     * 直接无脑遍历A和B,都遍历一遍,一个从A开始,一个从B开始
     * == 就退出,不==就接着遍历
     * 那么不会一直死循环下去,当二者都为null的时候也是跳出来了
     */
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode p = headA;
        ListNode q = headB;

        while (p!=q){
            if(p==null){
                p=headB;
            }else{
                p=p.next;
            }
            if(q==null){
                q=headA;
            }else{
                q=q.next;
            }
        }

        return p;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值