当当当!!!失踪人口回归啦,最近一直在补上课进度,所以博客有些落下了,今天是链表的一些常见面试题的解析!
移除链表元素
题目:
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
题目链接:移出链表元素——来试试
其实移出链表元素就是删除对应值的链表节点,操作无非记录要删除节点的上一个节点,使得这个节点指向要删除的节点的下一个节点,代码演示:
//preNode节点是要删除节点的上一个节点
//toDelNode节点是要删除的节点
preNode.next = toDelNode.next;
//更新节点
toDelNode = preNode.next;
“移出链表元素”和删除链表元素有所不同的是其明确的指出要移出“所有”符合的链表节点,其实不难,核心就是preNode节点和toDelNode始终保持着一前一后的关系来遍历操作删除链表元素即可.
代码难点:
- 要有意识的保护 preNode 和 DelNode 二者一前一后的位置关系
- 由于 perNode 和 DelNode 二者都是从 head 开始移动的,所以头节点是否是要删除的元素无法判断,所以要在循环体结束之后再进行一次判断,不要遗漏!!!
代码实现:
public ListNode removeElements(ListNode head, int val) {
//如果头节点是空的,那么就直接返回 null 就可以了
if(head == null){
return null;
}
//为防止toDelNode在进行比较的时候出现空引用错误,所以要判断head.next不为null
if(head.next == null && head.val == val){
return null;
}
//定义要删除的节点的上一个节点
ListNode preNode = head;
//定义要删除的节点
ListNode toDelNode = head.next;
//进入循环删除
while(toDelNode != null){
//如果toDelNode是对应的值,则开始删除节点
if(toDelNode.val == val){
preNode.next = toDelNode.next;
toDelNode = preNode.next;
}else{
//如果不是,则更新 preNode 和 toDelNode,使其始终保持一前一后
preNode = toDelNode;
toDelNode = preNode.next;
}
}
//由于toDelNode 的起点是 head.next,所以头节点是不是要删除的值无法判断
//在这里判断
if(head.val == val){
head = head.next;
}
return head;
}
反转链表
题目:
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
题目链接:反转链表
题目分析:在实现反转链表之前我们要简单了解一下Java的垃圾回收机制在链表中是怎样的,在链表中,一旦没有引用指向节点,那么链表就会被垃圾回收机制回收.而在反转链表中,将链表节点和节点之间的指向反转之后,如果没有引用指向反转后的链表和未反转的链表,那么二者都会回收.
反转链表其实并不难,但是光靠人脑来凭空想象还是比较难的,所以要画图来解释.
第一步:定义三个节点——before、cur、prev,三者作用分别为反转后的链表的头节点、保护反转后的链表、保护未反转的链表.
before指向null,cur和prev分别指向头节点
第二步:prev向下一个节点移动,同时开始反转链表,将第一个节点的next指向before,即cur.next = before;
此时,before仍旧指向null,cur指向第一个节点,prev指向第二个节点
第三步:第三步也是最后一步,先把before的指向向前移,使得before成为反转后链表的头节点,而cur保护反转后链表的使命也就达成了,将cur和prev再次到达一个起点,新的一轮反转开始!
自此,一个节点的反转就算是完成了,接下来只要不断循环,知道cur为null时也就整个链表完成了反转!
题目难点:
- 无时无刻要保证有引用指向反转后链表的头节点和待反转链表的头节点以免二者被垃圾回收机制回收
- 反转过程虽然简单,但是要注意代码的执行顺序,否则极易引起空引用异常
- 要辨明最后返回的是哪一个引用,不能搞混乱
代码实现
public ListNode reverseList(ListNode head) {
//特殊情况
if(head == null){
return null;
}
if(head.next == null){
return head;
}
ListNode before = null;
ListNode cur = head;
ListNode prev = head;
while(prev != null){
prev = cur.next;
cur.next = before;
before = cur;
cur = prev;
}
return before;
}
链表的中间节点
题目描述:
给定一个头结点为 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5]
输出:[3,4,5]
题目链接:链表的中间节点
题目解析:
本篇三道题目中,这道题是最简单,题目思路就是一个:找到中间节点,然后将中间节点作为头节点返回
第一步:先求出链表的长度length
int length = 0;
for(ListNode cur = head; cur != null; cur = cur.next){
length++;
}
第二步:找到中间节点
for(int i = 0; i < length / 2; i++){
cur = cur.next;
}
代码实现
public ListNode middleNode(ListNode head) {
if(head == null){
return null;
}
if(head.next == null){
return head;
}
int length = 0;
for(ListNode cur = head; cur != null; cur = cur.next){
length++;
}
ListNode cur = head;
for(int i = 0; i < length / 2; i++){
cur = cur.next;
}
return cur;
}
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。