Leetcode链表
Leetcode链表
一.闲聊
边学边刷的……慢慢写慢慢更
二.题目
1.移除链表元素
题干:
思路:
- 删除链表节点,就多了一个判断等值。
- 由于是单向链表,所以要删除节点时要找到目标节点的上一个节点,如果是双向链表,指向要删除节点本身即可
- 链表的头节点存在着被删除的风险,所以使用虚拟头节点来方便返回
代码:
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 Soulution{ public ListNode removeElements(ListNode head,int val){ //做个特判 if(head==null){ return head; } //以下两句可以用最后的构造器合并成一行。 ListNode dummy=new ListNode(0); dummy.next=head; ListNode cur=dummy; while(cur.next!=null){ if(cur.next.val==val){ cur.next=cur.next.next }else{ cur=cur.next; } } return dummy.next; } }
2.设计链表
题干:
思路:
- 一步步顺着实现各个接口即可,长个心眼就是addAtIndex这个功能可以在特殊情况如Head和Tail中进行调用,没必要在两个方法重新编写了。、
代码:
class MyLinkedList { int size; ListNode head; public MyLinkedList() { size=0; head=new ListNode(0); } public int get(int index) { if(index<0||index>=size){ return -1; } ListNode cur=head; for(int i=0;i<=index;i++){ cur=cur.next; } return cur.val; } public void addAtHead(int val) { addAtIndex(0,val); } public void addAtTail(int val) { addAtIndex(size,val); } public void addAtIndex(int index, int val) { if(index<0){ index=0; } if(index>size){ return; } size++; ListNode listNode=new ListNode(val); ListNode cur=head; for(int i=0;i<index;i++){ cur=cur.next; } listNode.next=cur.next; cur.next=listNode; } public void deleteAtIndex(int index) { if(index>=size||index<0){ return; } size--; ListNode cur=head; for(int i=0;i<index;i++){ cur=cur.next; } cur.next=cur.next.next; } } class ListNode{ int val; ListNode next; ListNode(){} ListNode(int val){ this.val=val; } }
这道题用了虚拟头节点,也可以理解为哨兵,目的是为了保证链表始终处于非空的状态。 而正由于存在虚拟头节点,所以与传统的链表操作存在不同,但思想一致。比如查找节点的值时,如果不存在虚拟头节点,那么我们循环index次即可,现在要循环index+1
次。
3.翻转链表
题干:反转一个单链表。 示例:示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
思路:
- 双指针法即可。一前一后配合
代码:
class Solution { public ListNode reverseList(ListNode head) { ListNode cur=head; ListNode pre=null; while (cur!=null){ //将下一个节点保存,否则就找不到下一个了 ListNode temp=cur.next; cur.next=pre; pre=cur; cur=temp; } return pre; } }
4.删除链表的倒数第N个节点
题干:
思路:
- 双指针,一快一慢,快的先走
n+1
步,保证慢指针最后会指向要删除节点的前一个节点,之后执行普通的删除节点操作即可 - 这题同样存在着删除头结点的情况,所以使用虚拟头节点方便处理
代码:
class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy=new ListNode(0); dummy.next=head; ListNode fast=dummy; ListNode slow=dummy; for(int i=0;i<=n;i++){ fast=fast.next; } while (fast!=null){ fast=fast.next; slow=slow.next; } slow.next=slow.next.next; return dummy.next; } }
5.链表相交
题干:
思路:
- 首先遍历第一个链表,其中会产生重复的部分必定不是两链表的相交点,所以可以利用哈希集合去重,并记录下每个节点。之后遍历第二条链表的同时在哈希集合中查找是否存在交集,存在的第一个交集即是链表的交点,之后的所有点都是共同点。
代码:
public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { Set<ListNode> set=new HashSet<ListNode>(); while (headA!=null){ set.add(headA); headA=headA.next; } while (headB!=null){ if(set.contains(headB)){ return headB; } headB=headB.next; } return null; } }
6.环形链表II
题干:
思路:
- 与链表相交题目相似,一种解法是同样可以利用哈希集合判断,遍历链表,当出现当前节点的下一节点已经存在于哈希集合当中时,我们就返回当前节点下一节点即可(也可以是当前节点出现在哈希集合中后,返回当前节点)
代码:
public class Solution { public ListNode detectCycle(ListNode head) { Set<ListNode> set=new HashSet<ListNode>(); ListNode cur=head; while (cur!=null){ if(set.contains(cur)){ return cur; }else{ set.add(cur); } cur=cur.next; } return null; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了