题目:给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点
示例 1:
输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
题目分析:
首先想到的是通过遍历整个链表,看是否存在这样一个与目标值相等的元素,如果有,则将这个数删除。如果没有,直接返回原始链表即可。
进一步分析:如果找到与目标值相等的结点,如果指针指向该结点,发现并不能删除该结点。因为我们的做法是当前结点的前一个结点的指针,指向当前结点的后一个结点(这样才能绕过目标结点),所以我们需要得到的是指向待删除结点的前一个结点的指针。
边界条件:
1. 如果删除第一个元素(单指针)
cur.data = targetNode.data
return cur.next;
2. 如果删除最后一个元素(单指针)
cur.next = null;
Java代码:
/**
* 【题目】: 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
* 返回删除后的链表的头节点
*/
public class Offer18 {
// 定义内部类
class Node{
int data; // 数据域
Node next; // 指针域
// 默认构造函数,初始化不带数据的头结点。
public Node() {
}
// 构造函数,用于创建结点。
public Node(int data){
this.data = data;
}
}
// 简易创建单链表
public Node creat(){
Node head = new Node(); // 创建一个不带数据的头结点。
Node x = head; // 备份头结点,用于创建链表。
// 简易创建一个链表
for (int i = 1; i <= 2100; i=i*2+3) {
x.next = new Node(i);
x = x.next;
}
return head;
}
// 输出单链表,输出测试。
public void showList(Node head){
// Node x = head;
Node x = head.next;
while (x!=null){
System.out.print(x.data+" ");
x = x.next;
}
System.out.println();
}
// 删除链表的结点
public Node deleteNode(Node head, int val) {
// 链表删除常规三部曲
// 1. 找到p.next.val == val;
// 2. p.next = p.next.next;
// 3. return head;
if(head.next==null){
return null;
}
Node cur = head;
// 当前结点的下一个结点以及下下一个结点不为空的时候,待删除的结点处于链表中间。
while(cur.next!=null && cur.next.next!=null){
// 如果待删除的结点是第一个元素。
if(cur.data == val){
return cur.next;
}
if(cur.next.data == val){
cur.next = cur.next.next;
}
cur = cur.next;
}
// 退出循环,可能是cur的下一个结点为空,也可能是下下一个结点为空
// 考虑是最后一个元素待删除
if (cur.next!=null && cur.next.next==null && cur.next.data == val){
cur.next = null;
}
return head;
}
public static void main(String[] args) {
Offer18 offer18 = new Offer18();
Node list1 = offer18.creat();
System.out.println("链表:");
offer18.showList(list1);
System.out.println("删除目标节点后:");
list1 = offer18.deleteNode(list1,2045);
offer18.showList(list1);
}
}
【注】
(1):leetcode 等平台只要我们完成一个函数即可,本人初出茅庐,为了巩固基本知识,故自己补充了部分代码,用于练手。
(2):一定要将头中尾三种情况都考虑清楚。