【LeetCode 随笔】面试经典 150 题【中等+困难】持续更新中。。。

在这里插入图片描述

🌈你好呀!我是 山顶风景独好
💕欢迎来到我的博客,很高兴能够在这里和您见面!
💕希望您在这里可以感受到一份轻松愉快的氛围!
💕这里不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
🚀 欢迎一起踏上探险之旅,挖掘无限可能,共同成长!

138.【中等】随机链表的复制

题目描述

  • 给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
  • 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
  • 例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。
  • 返回复制链表的头节点。
  • 用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
  • val:一个表示 Node.val 的整数。
  • random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
  • 你的代码 只 接受原链表的头节点 head 作为传入参数。

示例 1:
在这里插入图片描述

  • 输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
  • 输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

示例 2:
在这里插入图片描述

  • 输入:head = [[1,1],[2,1]]
  • 输出:[[1,1],[2,1]]

示例 3:
在这里插入图片描述

  • 输入:head = [[3,null],[3,0],[3,null]]
  • 输出:[[3,null],[3,0],[3,null]]
/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/

class Solution {  
    public Node copyRandomList(Node head) {  
        // 如果原链表为空,则直接返回null  
        if(head == null) return null;  
  
        // 定义一个指针cur,用于遍历原链表  
        Node cur = head;  
  
        // 1. 复制各节点,并构建拼接链表  
        // 遍历原链表,在每个节点后面复制一个新的节点,并链接到原节点的next  
        while(cur != null) {  
            // 创建一个新节点tmp,其值与当前节点cur相同  
            Node tmp = new Node(cur.val);  
            // 将新节点tmp的next指向当前节点cur的下一个节点  
            tmp.next = cur.next;  
            // 将当前节点cur的next指向新节点tmp,实现新旧节点的拼接  
            cur.next = tmp;  
            // 移动cur到下一个节点  
            cur = tmp.next;  
        }  
  
        // 2. 构建各新节点的 random 指向  
        // 再次遍历原链表(实际上是新旧节点拼接的链表),设置新节点的random指针  
        cur = head;  
        while(cur != null) {  
            // 如果当前节点cur的random指针不为空  
            if(cur.random != null)  
                // 将当前节点cur的下一个节点(即新节点)的random指向原节点cur的random指针的下一个节点(即对应的新节点)  
                cur.next.random = cur.random.next;  
            // 移动cur到下一个新旧节点对  
            cur = cur.next.next;  
        }  
  
        // 3. 拆分两链表  
        // 将新旧节点拼接的链表拆分为两个独立的链表:原链表和新链表  
        cur = head.next; // cur指向新链表的头节点  
        Node pre = head, res = head.next; // pre用于遍历原链表,res用于保存新链表的头节点  
  
        // 遍历链表,拆分新旧节点  
        while(cur.next != null) {  
            // 将原链表的当前节点pre的next指向下一个新节点  
            pre.next = pre.next.next;  
            // 将新链表的当前节点cur的next指向下一个新节点  
            cur.next = cur.next.next;  
            // 移动pre和cur到下一个节点  
            pre = pre.next;  
            cur = cur.next;  
        }  
  
        // 单独处理原链表的尾节点,将其next置为null  
        pre.next = null;   
  
        // 返回新链表的头节点  
        return res;  
    }  
}

92.【中等】反转链表 II

题目描述
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

示例 1:
在这里插入图片描述

  • 输入:head = [1,2,3,4,5], left = 2, right = 4
  • 输出:[1,4,3,2,5]

示例 2:

  • 输入:head = [5], left = 1, right = 1
  • 输出:[5]
class Solution {  
    // 反转从位置 left 到 right 的链表部分  
    public ListNode reverseBetween(ListNode head, int left, int right) {  
        // 创建一个哑节点dummy,它的next指向head,这样可以避免处理头节点为null或left为1的特殊情况  
        ListNode dummy = new ListNode(0, head);  
        // p0指针用于找到需要反转部分的起始位置的前一个节点  
        ListNode p0 = dummy;  
  
        // 移动p0指针到left位置的前一个节点  
        for (int i = 0; i < left - 1; ++i)  
            p0 = p0.next;  
  
        // pre指针用于反转过程中的前一个节点  
        ListNode pre = null;  
        // cur指针指向当前需要处理的节点  
        ListNode cur = p0.next;  
  
        // 反转从left到right的链表部分  
        for (int i = 0; i < right - left + 1; ++i) {  
            // nxt指针暂存cur的下一个节点,因为下一步cur.next会被修改  
            ListNode nxt = cur.next;  
            // 将cur的next指针指向前一个节点,实现反转  
            cur.next = pre;  
            // pre指针向后移动  
            pre = cur;  
            // cur指针向后移动  
            cur = nxt;  
        }  
  
        // 将p0的next指针指向反转后的部分的最后一个节点(即原来的right位置的节点)  
        // 这一步很重要,因为它连接了反转部分和原链表的其他部分  
        p0.next.next = cur;  
        // 将p0的next指针指向反转后的部分的头节点(即原来的left位置的节点)  
        // 这一步将反转部分与原链表的其他部分连接起来  
        p0.next = pre;  
  
        // dummy.next是反转后整个链表的头节点,所以返回它  
        return dummy.next;  
    }  
}

25.【困难】K 个一组翻转链表

题目描述

  • 给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
  • k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
  • 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例 1:
在这里插入图片描述

  • 输入:head = [1,2,3,4,5], k = 2
  • 输出:[2,1,4,3,5]
    示例 2:
    在这里插入图片描述
  • 输入:head = [1,2,3,4,5], k = 3
  • 输出:[3,2,1,4,5]
class Solution {  
    // 反转链表中每k个节点  
    public ListNode reverseKGroup(ListNode head, int k) {  
        // 创建一个哑节点(hair node),方便处理头节点反转的情况  
        ListNode hair = new ListNode(0);  
        hair.next = head;  
        // pre指针用于指向当前需要反转的k个节点的前一个节点  
        ListNode pre = hair;  
  
        // 当头节点不为空时,循环进行反转  
        while (head != null) {  
            // tail指针用于指向当前需要反转的k个节点的最后一个节点  
            ListNode tail = pre;  
            // 查看剩余部分长度是否大于等于 k  
            // 如果剩余长度小于k,则无需再反转,直接返回结果  
            for (int i = 0; i < k; ++i) {  
                tail = tail.next;  
                if (tail == null) {  
                    // 如果tail为null,说明剩余节点不足k个,直接返回结果  
                    return hair.next;  
                }  
            }  
            // nex指针用于保存tail的下一个节点,即下一个需要反转的k个节点的头节点  
            ListNode nex = tail.next;  
            // 调用myReverse方法反转当前k个节点,并返回反转后的头尾节点  
            ListNode[] reverse = myReverse(head, tail);  
            // 更新head为反转后的头节点  
            head = reverse[0];  
            // 更新tail为反转后的尾节点  
            tail = reverse[1];  
            // 把子链表重新接回原链表  
            // pre.next指向反转后的头节点  
            pre.next = head;  
            // tail.next指向下一个需要反转的k个节点的头节点  
            tail.next = nex;  
            // pre指针移动到当前反转的k个节点的尾节点  
            pre = tail;  
            // head指针移动到下一个需要反转的k个节点的头节点  
            head = tail.next;  
        }  
  
        // 返回反转后的链表头节点  
        return hair.next;  
    }  
  
    // 反转链表中的节点,从head到tail(不包括tail)  
    public ListNode[] myReverse(ListNode head, ListNode tail) {  
        // prev指针用于指向反转后的前一个节点,初始为tail的下一个节点  
        ListNode prev = tail.next;  
        ListNode p = head;  
        while (prev != tail) {  
            // nex指针用于保存p的下一个节点  
            ListNode nex = p.next;  
            // 反转p的指向  
            p.next = prev;  
            // prev向后移动  
            prev = p;  
            // p向前移动  
            p = nex;  
        }  
        // 返回反转后的头尾节点数组  
        return new ListNode[]{tail, head};  
    }  
}

19.【中等】删除链表的倒数第 N 个结点

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

示例 1:
在这里插入图片描述

  • 输入:head = [1,2,3,4,5], n = 2
  • 输出:[1,2,3,5]
    示例 2:
  • 输入:head = [1], n = 1
  • 输出:[]
    示例 3:
  • 输入:head = [1,2], n = 1
  • 输出:[1]
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {  
    // 定义一个方法,用于从链表的末尾删除第n个节点  
    public ListNode removeNthFromEnd(ListNode head, int n) {  
        // 创建一个虚拟头节点dummy,其值为0,并指向原链表的头节点head  
        // 这样做的目的是为了方便处理删除头节点的情况  
        ListNode dummy = new ListNode(0, head);  
          
        // 定义两个指针first和second,都初始化为链表的头节点  
        // first指针用于先走n步,以确定与second指针之间的间隔  
        ListNode first = head;  
        ListNode second = dummy;  
          
        // first指针先走n步  
        for (int i = 0; i < n; ++i) {  
            first = first.next;  
        }  
          
        // 当first指针到达链表末尾时,second指针指向的下一个节点即为要删除的节点的前一个节点  
        // 通过移动first和second指针,保持它们之间的间隔始终为n  
        while (first != null) {  
            first = first.next;  
            second = second.next;  
        }  
          
        // 删除second指针指向的下一个节点(即要删除的节点)  
        // 通过将second.next指向second.next.next来实现  
        second.next = second.next.next;  
          
        // 返回新的链表的头节点(由于我们使用了dummy,所以实际返回的是dummy.next)  
        ListNode ans = dummy.next;  
        return ans;  
    }  
}  

82.【中等】删除排序链表中的重复元素 II

给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。

示例 1:
在这里插入图片描述

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

示例 2:
在这里插入图片描述

  • 输入:head = [1,1,1,2,3]
  • 输出:[2,3]
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {  
    // 定义一个方法,用于删除链表中重复的元素  
    public ListNode deleteDuplicates(ListNode head) {  
        // 如果链表为空,则直接返回  
        if (head == null) {  
            return head;  
        }  
  
        // 创建一个虚拟头节点dummy,其值为0,并指向原链表的头节点head  
        // 这样做是为了方便处理删除头节点的情况  
        ListNode dummy = new ListNode(0, head);  
  
        // cur指针初始化为虚拟头节点dummy,用于遍历链表  
        ListNode cur = dummy;  
  
        // 当cur的下一个节点和再下一个节点都不为空时,进行循环  
        while (cur.next != null && cur.next.next != null) {  
            // 如果cur的下一个节点和再下一个节点的值相等,说明有重复元素  
            if (cur.next.val == cur.next.next.val) {  
                // 记录当前重复元素的值  
                int x = cur.next.val;  
  
                // 删除所有值为x的节点,直到cur的下一个节点的值不再等于x  
                while (cur.next != null && cur.next.val == x) {  
                    cur.next = cur.next.next; // 删除当前重复节点  
                }  
            } else {  
                // 如果没有重复元素,cur指针向后移动一位  
                cur = cur.next;  
            }  
        }  
  
        // 遍历结束后,返回处理后的链表的头节点(虚拟头节点的下一个节点)  
        return dummy.next;  
    }  
}  

✨ 这就是今天要分享给大家的全部内容了,我们下期再见!😊

🏠 我在CSDN等你哦!我的主页😍

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值