力扣-《剑指offer》-链表-刷题笔记
创始人
2025-05-29 05:53:43
0

目录

第一题:从尾到头打印链表

第二题:删除链表的节点

第三题:链表中倒数第k个节点

第四题:反转链表

第五题:合并两个排序的链表

第六题:两个链表的第一个公共节点


第一题:从尾到头打印链表

 官方答案:栈

class Solution {public int[] reversePrint(ListNode head) {Stack stack = new Stack();//定义⼀个栈,栈内元素后进先出ListNode temp = head;//创建⼀个头指针while (temp != null) {//当前指针不为空stack.push(temp);//将指针指向的节点压⼊栈内temp = temp.next;//指针后移}int size = stack.size();//获取栈的⼤⼩int[] print = new int[size];//创建⼀个新数组for (int i = 0; i < size; i++) {print[i] = stack.pop().val;//弹出栈内的值存⼊到数组}return print;}
}

网友答案:递归

class Solution {ArrayList tmp = new ArrayList();//创建新的数组链表public int[] reversePrint(ListNode head) {recur(head);//倒转链表int[] res = new int[tmp.size()];//创建新数组for(int i = 0; i < res.length; i++)res[i] = tmp.get(i);//把数组链表temp转化为数组resreturn res;}void recur(ListNode head) {//递归体if(head == null) return;recur(head.next);//递归⼊⼝,层层递归,递归没有结束时,下⾯这句语句是⽆法执⾏的tmp.add(head.val);//递归结束了,开始层层回溯,把当前节点值加⼊列表//上⾯的递归和回溯过程总体上看,就像⼀个U型滑板场}
}
//我写题时,就是来到单链表尾部后就不知道怎么回去了

简化后的递归:

class Solution {int[] res;int i = 0;int j = 0;public int[] reversePrint(ListNode head) {solve(head);return res;}public void solve(ListNode head){//递归体if(head == null){res = new int[i];return;}i++;solve(head.next);res[j] = head.val;j++;}
}

第二题:删除链表的节点

 网友答案:双指针

class Solution {public ListNode deleteNode(ListNode head, int val) {if(head.val == val) return head.next;//要删除的是头节点,就直接返回头节点的下⼀个节点就⾏了ListNode pre = head, cur = head.next;//定义两个指针,cur表示当前节点,它将指向要删除的节点,pre指向当前节点的前⼀个节点while(cur != null && cur.val != val) {pre = cur;cur = cur.next;//两个指针都往后移⼀步,cur和pre始终处于前后位置}if(cur != null) pre.next = cur.next;//pre.next原本应该是curreturn head;}
}

网友答案:单指针

class Solution {public ListNode deleteNode(ListNode head, intval) {if (head == null) return null;if (head.val == val) return head.next;ListNode cur = head;while (cur.next != null && cur.next.val !=val)//注意这⾥是cur.next.val,如果是cur.val==val,即cur为要删除的节点,//但再往回⼀步,来到前节点改变它的后指向很麻烦,所以直接判断当前节点的下⼀个节点的值cur = cur.next;if (cur.next != null)cur.next = cur.next.next;return head;}
}//我写题时,主要问题是,我⽤head当成指针往后⾛,删掉元素后,head 回不到头部,直接返回head,得到的结果不完整。所以,应该⽤⼀个新指针来遍历链表

网友答案:递归

class Solution {public ListNode deleteNode(ListNode head, int val) {if (head == null) {return null;}if (head.val == val) {return head.next;} else {head.next = deleteNode(head.next, val);}return head;}
}
//空间复杂度为O(n),效率⽐双指针低

第三题:链表中倒数第k个节点

 官方答案:

法一:顺序法

class Solution {public ListNode getKthFromEnd(ListNode head, int k) {int n = 0;ListNode node = null;for (node = head; node != null; node = node.next) {n++;}for (node = head; n > k; n--) {node = node.next;}return node;}
}
//思路和我的⼀样,但代码整体上⽐我的要集中⼀点,我的写得有点散

法二:快慢指针

class Solution {public ListNode getKthFromEnd(ListNode head, int k) {ListNode fast = head;//快指针ListNode slow = head;//慢指针while (fast != null && k > 0) {//当快指针⾛了k步时,慢指针才出发,它们之间的步数差永远为kfast = fast.next;k--;}while (fast != null) {//当快指针⾛到尽头时,慢指针刚好在它前k个位置fast = fast.next;slow = slow.next;}return slow;}
}

网友答案:栈

class Solution {public ListNode getKthFromEnd(ListNode head, int k) {Deque d = new ArrayDeque<>();while (head != null) {//将所有节点都压⼊栈中d.addLast(head);head = head.next;}ListNode ans = null;while (k-- > 0) ans = d.pollLast();//从栈顶弹出k个元素,最后⼀个出栈的元素即为所求return ans;}
}

第四题:反转链表

 官方答案:

法一:

class Solution {public ListNode reverseList(ListNode head) {ListNode prev = null;//原链表的第⼀个节点反//转后必须指向空,否则链表中可能会产⽣环,因为此节点原来就//是指向第⼆个节点的,如果不改变它的指向,反转链表后,它还//是指向第⼆个节点ListNode curr = head;while (curr != null) {ListNode next = curr.next;//存储节点,此时尚未引⽤,防⽌被覆盖curr.next = prev;//把当前节点的next指针改为指向前⼀个节点prev = curr;//节点都往后移⼀位curr = next;}return prev;//返回头引⽤}
}

法二:递归

class Solution {public ListNode reverseList(ListNode head) {if (head == null || head.next == null) {//递归到尽头的条件return head;}ListNode newHead =reverseList(head.next);//层层递进,head最终来到链表的//尾部,链表最后⼀个节点成为新的头引⽤head.next.next = head;head.next = null;//head.next = null; 网友理解的是每次反转完成之后就把尾巴上的指                        //针翘起来指向天空,等着后面的大哥接上。 head.next.next = head;这句 //话只是把翘起来的指针插自己身上了。完事之后,自己也翘起来 head.next = null;return newHead;//层层回溯时,返回的是不断往前缩短的链表的最后⼀个元素}
}

网友答案:

class Solution {public ListNode reverseList(ListNode head) {ListNode cur = head, pre = null;while(cur != null) {ListNode tmp = cur.next; // 暂存后继节点cur.nextcur.next = pre; // 修改 next 引⽤指向pre = cur; // pre 暂存 curcur = tmp; // cur 访问下⼀节点}return pre;}
}

网友答案:

class Solution {public ListNode reverseList(ListNode head) {return recur(head, null); // 调⽤递归并返回}private ListNode recur(ListNode cur, ListNode pre) {if (cur == null) return pre; // 终⽌条件ListNode res = recur(cur.next, cur); // 递归后继节点cur.next = pre; // 修改节点引⽤指向return res; // 返回反转链表的头节点}
}

第五题:合并两个排序的链表

 官方答案:

法一:递归

class Solution {public ListNode mergeTwoLists(ListNode l1, ListNode l2) {if (l1 == null) {return l2;} else if (l2 == null) {return l1;} else if (l1.val < l2.val) {l1.next = mergeTwoLists(l1.next, l2);return l1;} else {l2.next = mergeTwoLists(l1, l2.next);return l2;}}
}

法二:双指针

class Solution {public ListNode mergeTwoLists(ListNode l1, ListNode l2) {ListNode prehead = new ListNode(-1);//设定⼀个哨兵节点preheadListNode prev = prehead;//维护⼀个prev指针,不断地往后移,调整next指针是指向l1还是l2while (l1 != null && l2 != null) {if (l1.val <= l2.val) {prev.next = l1;//l1表示链表1的当前节点,prev.next=l1表示把链表1的当前节点接⼊前⾯的合并链表l1 = l1.next;//l1指针往后移⼀位} else {prev.next = l2;l2 = l2.next;}prev = prev.next;//⽆论prev指针指向l1还是l2,它都要往后移一位}
// 合并后 l1 和 l2 最多只有⼀个还未被合并完,我们直接将链表末尾指向未合并完的链表即可prev.next = l1 == null ? l2 : l1;//l1和l2肯定⾄少有⼀个为空了return prehead.next;}
}

第六题:两个链表的第一个公共节点

 看不懂题目,觉得输入里不是已经包括答案了吗?还写什么?

 官方答案:

法一:哈希集合

public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {Set visited = new HashSet();//新建一个哈希集合ListNode temp = headA;//指针temp指向链表Awhile (temp != null) {visited.add(temp);//把链表A的每个节点都加入哈希集合temp = temp.next;}temp = headB;//指针temp指向链表Bwhile (temp != null) {if (visited.contains(temp)) {//遍历链表B,判断是否和A有相同节点return temp;}temp = temp.next;}return null;//两个链表不相交}
}

法二:双指针

public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {if (headA == null || headB == null) {return null;}ListNode pA = headA, pB = headB;while (pA != pB) {//两个指针是同步走的,无论两个链表的长度关系如何,//只要链表相交,那两个指针一定会同时到达第一个公共节点pA = pA == null ? headB : pA.next;pB = pB == null ? headA : pB.next;}return pA;}
}

 

 

 网友答案:枚举法

public class Solution {public ListNode getIntersectionNode(ListNode a, ListNode b) {for (ListNode h1 = a; h1 != null ; h1 = h1.next) {//双层for循环for (ListNode h2 = b; h2 != null ; h2 = h2.next) {if (h1 == h2) return h1;}}return null;}
}

网友答案:队列

public class Solution {public ListNode getIntersectionNode(ListNode a, ListNode b) {Deque d1 = new ArrayDeque<>(), d2 = new ArrayDeque<>();//栈是后进先出while (a != null) {//把链表a的所有节点压入栈d1.add(a);a = a.next;}while (b != null) {//把链表b的所有节点压入栈d2.add(b);b = b.next;}ListNode ans = null;while (!d1.isEmpty() && !d2.isEmpty() && d1.peekLast() == d2.peekLast()) {d1和d2都不为空时,循环比较栈顶元素ans = d1.pollLast();//记录上一位栈顶元素,一旦遇到第一个不同的节点,就结束循环d2.pollLast();}return ans;}
}

网友答案:Set

public class Solution {public ListNode getIntersectionNode(ListNode a, ListNode b) {Set set = new HashSet<>();while (a != null) {//记录链表a的所有节点set.add(a);a = a.next;}while (b != null && !set.contains(b)) b = b.next;//遍历链表b,检查当前节点是否在set中出现过,第一个出现过的节点即是交点return b;}
}

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
JAVA多线程知识整理 Java多线程基础 线程的创建和启动 继承Thread类来创建并启动 自定义Thread类的子类&#...
【洛谷 P1090】[NOIP... [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G ...
国民技术LPUART介绍 低功耗通用异步接收器(LPUART) 简介 低功耗通用异步收发器...
城乡供水一体化平台-助力乡村振... 城乡供水一体化管理系统建设方案 城乡供水一体化管理系统是运用云计算、大数据等信息化手段࿰...
程序的循环结构和random库...   第三个参数就是步长     引入文件时记得指明字符格式,否则读入不了 ...
中国版ChatGPT在哪些方面... 目录 一、中国巨大的市场需求 二、中国企业加速创新 三、中国的人工智能发展 四、企业愿景的推进 五、...
报名开启 | 共赴一场 Flu... 2023 年 1 月 25 日,Flutter Forward 大会在肯尼亚首都内罗毕...
汇编00-MASM 和 Vis... Qt源码解析 索引 汇编逆向--- MASM 和 Visual Studio入门 前提知识ÿ...
【简陋Web应用3】实现人脸比... 文章目录🍉 前情提要🌷 效果演示🥝 实现过程1. u...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
windows安装JDK步骤 一、 下载JDK安装包 下载地址:https://www.oracle.com/jav...
分治法实现合并排序(归并排序)... 🎊【数据结构与算法】专题正在持续更新中,各种数据结构的创建原理与运用✨...
在linux上安装配置node... 目录前言1,关于nodejs2,配置环境变量3,总结 前言...
Linux学习之端口、网络协议... 端口:设备与外界通讯交流的出口 网络协议:   网络协议是指计算机通信网...
Linux内核进程管理并发同步... 并发同步并发 是指在某一时间段内能够处理多个任务的能力,而 并行 是指同一时间能够处理...
opencv学习-HOG LO... 目录1. HOG(Histogram of Oriented Gradients,方向梯度直方图)1...
EEG微状态的功能意义 导读大脑的瞬时全局功能状态反映在其电场结构上。聚类分析方法一致地提取了四种头表面脑电场结构ÿ...
【Unity 手写PBR】Bu... 写在前面 前期积累: GAMES101作业7提高-实现微表面模型你需要了解的知识 【技...