您的位置:首页 > 房产 > 建筑 > 【LeetCode 随笔】面试经典 150 题【中等+困难】持续更新中。。。

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

2024/12/27 15:52:10 来源:https://blog.csdn.net/shiranyyds/article/details/139322115  浏览:    关键词:【LeetCode 随笔】面试经典 150 题【中等+困难】持续更新中。。。

在这里插入图片描述

文章目录

    • 138.【中等】随机链表的复制
    • 92.【中等】反转链表 II
    • 25.【困难】K 个一组翻转链表
    • 19.【中等】删除链表的倒数第 N 个结点
    • 82.【中等】删除排序链表中的重复元素 II

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

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等你哦!我的主页😍

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com