当前位置: 首页 > ops >正文

【算法训练营Day04】链表part2

文章目录

  • 两两交换链表中的节点
  • 删除链表的倒数第 N 个结点
  • 链表相交
  • 环形链表 II
  • 链表总结

两两交换链表中的节点

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

算法逻辑:

  • 添加一个虚拟头节点
  • 初始化一个交换指针,代表每次交换指针的后两个节点,该指针从虚拟头节点开始移动
  • 接下来就是交换步骤
    • 先将交换指针的后面第一个节点(简称后1节点)以及交换指针的后3节点存起来
    • 将交换指针的后2节点与交换指针节点进行缝合
    • 将存起来的后1节点与后2节点进行缝合
    • 在将存起来的后3节点与后1节点进行缝合
  • 如此交换直到交换指针节点为null,或者后1节点为null,或者后2节点为null,因为必须要有两个节点才能交换
/*** 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 swapPairs(ListNode head) {if(head == null || head.next == null) return head;ListNode virtualHead = new ListNode(-1,head);ListNode exchangePointer = virtualHead;while(exchangePointer != null && exchangePointer.next != null && exchangePointer.next.next != null) {ListNode temp1 = exchangePointer.next;ListNode temp3 = temp1.next.next;exchangePointer.next = exchangePointer.next.next;exchangePointer.next.next = temp1;exchangePointer.next.next.next = temp3;exchangePointer = exchangePointer.next.next;}return virtualHead.next;}
}

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

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

逻辑思路:
这道题既然是删除倒数的第n个节点,那么我们可以将链表反转,然后再删除第n个,最后再把链表反转回去即可。我们前几天的训练营中做过移除链表元素、翻转链表等算法题,所以这里直接把相关方法移植过来即可。

代码:

/*** 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 removeNthFromEnd(ListNode head, int n) {ListNode reverseList = reverseList(head);ListNode deleteList = deleteAtCount(reverseList,n);return reverseList(deleteList);}public ListNode reverseList(ListNode head) {ListNode reverseResultVirtualHead = new ListNode();ListNode pointer = head;while(pointer != null) {ListNode currentNode = new ListNode(pointer.val,null);currentNode.next = reverseResultVirtualHead.next;reverseResultVirtualHead.next = currentNode;pointer = pointer.next;}return reverseResultVirtualHead.next;}public ListNode deleteAtCount(ListNode head,int count) {ListNode virtualHead = new ListNode(-1,head);ListNode pointer = virtualHead;while(count > 0 && pointer.next != null) {if(count == 1) {pointer.next = pointer.next.next;}count -= 1;pointer = pointer.next;}return virtualHead.next;}
}

链表相交

题目链接:面试题 02.07. 链表相交

算法逻辑:
读完题目之后可以发现一个特点那就是若链表相交,那么必有公共后缀!我们若想找到两个链表的公共后缀那么第一想法肯定就是反向遍历。但是这是一个单向链表,直接反向遍历无法实现,这个时候我们就可以借助于栈结构来完成公共后缀的比对。

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*/
public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {if(headA == null || headB == null) return null;ListNode pointerA = headA;ListNode pointerB = headB;Stack<ListNode> a = new Stack<ListNode>();Stack<ListNode> b = new Stack<ListNode>();while(pointerA != null) {a.push(pointerA);pointerA = pointerA.next;}while(pointerB != null) {b.push(pointerB);pointerB = pointerB.next;}ListNode nodeA = a.pop();ListNode nodeB = b.pop();ListNode result = null;while(nodeA == nodeB) {result = nodeA;if (a.empty() || b.empty()) break;nodeA = a.pop();nodeB = b.pop();}return result;}
}

环形链表 II

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

解题思路:

判断是否成环,换一句话说也就是在遍历链表的时候看是否有重复的节点,第一个重复的节点就是成环的起点。我们可以利用set数据结构,每遍历到一个新节点就看set中是否有相同节点,如果没有就添加到set中,如果有则说明该节点就是成环节点。遍历完了都没有重复节点,则说明不成环。

代码:

/*** Definition for singly-linked list.* class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*/
public class Solution {public ListNode detectCycle(ListNode head) {Set<ListNode> nodeSet = new HashSet();ListNode pointer = head;while(pointer != null) {if(nodeSet.contains(pointer)) return pointer;nodeSet.add(pointer);pointer = pointer.next;}return null;}
}

链表总结

链表的关键点就在于:

  • 增加、删除的时候可以引入虚拟头节点,让逻辑更加统一,不用单独考虑一些边界情况
  • 如果是遍历等不会修改链表结构的操作则无需引入虚拟头节点
  • 增加删除的重点就在于增加、删除元素的前后链要是可见的,才能完成相关的节点缝合工作。这就需要我们引入一些中间变量来存储这些前后链.
http://www.xdnf.cn/news/10193.html

相关文章:

  • mkcert实现本地https
  • Kafka 如何保证顺序消费
  • GitHub 趋势日报 (2025年05月30日)
  • DeepSeek 赋能自动驾驶仿真测试:解锁高效精准新范式
  • 前端面经 DNSxieyi1
  • Go语言的context
  • 第4节 Node.js NPM 使用介绍
  • linux 1.0.6
  • BFD 基本工作原理与实践:如何与 VRRP 联动实现高效链路故障检测?
  • 数据库运维管理系统在AI方向的实践
  • 【拓扑排序】P7150 [USACO20DEC] Stuck in a Rut S|普及+
  • AnyTXT Searcher 文档内容搜索工具 v1.3.2034 官方版
  • LeetCode - 面试题 02.04. 分割链表
  • gcc相关内容
  • 单例模式的类和静态方法的类的区别和使用场景
  • python打卡day41
  • bert扩充或者缩小词表
  • 企业AI部署热潮下的安全隐忧:速度与安全的博弈
  • QT入门学习
  • 电脑驱动程序更新工具, 3DP Chip 中文绿色版,一键更新驱动!
  • 【基础算法】高精度(加、减、乘、除)
  • 【iOS】方法交换
  • 【SpringBoot实战】优雅关闭服务
  • 【NLP 78、手搓Transformer模型结构及实战】
  • 34.x64汇编写法(一)
  • stm32——I2C协议
  • 第三方软件评测机构如何助力软件品质提升及企业发展?
  • 微信小程序真机调试时如何实现与本地开发环境服务器交互
  • 27 C 语言编程核心:main 主函数(基本形式、返回值、参数、命令行传参)、多文件编程实践
  • 设计模式——面向对象设计六大原则