剑指 Offer 18. 删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
注意:此题对比原题有改动
示例 1:
输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:
输入: head = [4,5,1,9], val = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
题目保证链表中节点的值互不相同
若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点
思路
删除链表结点这种题目,翻了翻,之前写过三篇文章:
第1篇包括两道题
第一道题是只给出一个当前节点,没有给出头结点,让把当前节点删除掉。方法是将当前节点的下一个节点的val和next都赋值给当前节点。
第二道题是删除链表中的所有与某一个val相等的节点,也就是给定的链表有可能会有多个值
解决办法有:
- 递归
- 建立虚拟头结点,虚拟头结点的next = head
preNode = head;
然后找preNode.next.val 是否等于 val
第2篇是:
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
解决方法有:
- 递归
- 判断currentNode.next是否为null,然后做遍历
第3篇与第1篇中的第二道题是同一道题
解法上也是一样,使用虚拟头结点dummyHead,然后使dummyHead.next = head;
新建ListNode preNode = dummyHead;
然后找preNode.next.val 是否等于 val
以下,分别尝试使用三种方法来解决该题:
方法一:不使用虚拟头结点
class Solution {
public ListNode deleteNode(ListNode head, int val) {
//判断边界值
if(head == null) return head;
//由于要返回的是原来的链表,直接操作head就找不到原来的链表了
//因此,需要定义一个临时结点,也可以叫做currentNode
ListNode tempNode = head;
//由于值的比较是从tempNode.next.val开始,也就是tempNode.val没有做比较
//单独拿出来第一个元素做比较
//此题元素不重复,因此if就可以
//如果元素重复,那么这里需要改成while循环
if(tempNode.val == val) return tempNode.next;
while(tempNode.next != null){
if(tempNode.next.val == val){
tempNode.next = tempNode.next.next;
}else{
tempNode = tempNode.next;
}
}
return head;
}
}
方法二:使用虚拟头结点
class Solution {
public ListNode deleteNode(ListNode head, int val) {
//判断边界值
if(head == null) return head;
//建立虚拟头结点
ListNode dummyHead = new ListNode();
dummyHead.val = -1;
dummyHead.next = head;
ListNode preNode = dummyHead;
//不需要进行比较第一个元素了
// if(tempNode.val == val) return tempNode.next;
while(preNode.next != null){
if(preNode.next.val == val){
preNode.next = preNode.next.next;
}else{
preNode = preNode.next;
}
}
//返回虚拟头结点的下一个元素
return dummyHead.next;
}
}
方法三:递归
class Solution {
public ListNode deleteNode(ListNode head, int val) {
//判断边界值
if(head == null) return head;
head.next = deleteNode(head.next, val);
if(head.val == val){
return head.next;
}else{
return head;
}
}
}