title: 删除链表节点
date: 2018-08-06 08:28:59
tags: 剑指offer
1. 题目
在 O(1) 时间内删除链表节点。
给定单向链表节点的头指针和一个节点指针(使用 java 实现,因此我的代码中头结点作为一个变量定义在类中),定义一个函数在 O(1) 时间内删除该节点。
2. 思路
在单向链表中删除节点按照常规的思路来说就是从头开始遍历,查找到需要删除的节点,并在链表中删除该节点。但是这种做法的时间复杂度为 O(N),并不符合题目要求,因此需要考虑一下其他的思路。
首先,看一下链表内部使用的数据结构:
private class Node{
private Object value;
private Node next;
public Node(Object value,Node next){
this.value = value;
this.next = next;
}
}
一个节点包含这个节点的值以及下一个节点的引用。如果要删除这个节点的值,可以通过将下一个节点的内容复制到要删除的这个节点,通过这样的动作也是可以删除节点的。例如,有这样的一个链表:
1 -> 2 -> 3 -> 4 -> 5
如果要删除 3 这个节点,那么,我们可以将 4 这个节点的值覆盖 3 这个节点的值,用 4 这个节点的 next 变量覆盖 3 这个节点的 next 变量,这个过程下来,链表中就将 3 这个节点删除了。
但是这个过程需要注意,如果这个节点是最后一个节点,就没办法通过上述的方法来完成,只能通过常规的方法来解决了。
还有一个情况需要注意,如果这个节点是头结点并且整个链表中只有一个节点,这时候我们就需要将链表的头结点置为空。代码的实现如下:
private Node head;
private Node tail;
public void deleteNode(Node toBeDelete){
if(head==null || toBeDelete==null)
return;
if(toBeDelete.next!=null){
Node nextNode = toBeDelete.next;
toBeDelete.value = nextNode.value;
toBeDelete.next = nextNode.next;
}else if(head.value.equals(toBeDelete.value)){
head = null;
tail = null;
}else{
Node currentNode = head;
while(!toBeDelete.value.equals(currentNode.next.value)){
currentNode = currentNode.next;
}
currentNode.next = null;
}
}
// 打印链表的方法
public void printLinkList(){
Node currentNode = head;
while(currentNode!=null){
System.out.println(currentNode.value);
currentNode = currentNode.next;
}
}
// 链表添加元素的方法
public void add(Object value){
Node temp = new Node(value,null);
if(head==null){
head = temp;
tail = temp;
}else{
tail.next = temp;
tail = tail.next;
}
}
3. 注意点
这个方法的时间复杂度是不是 O(1) 呢?答案是肯定的,其时间复杂度为 [ (n-1)*O(1) + O(n) ] / n = O(1)。
这个思路是基于一个假设上实现的,就是要删除的元素需要在链表内,为了符合时间复杂度为 O(1) 的要求,就没办法在函数中进行判断,因此需要由调用该函数的人来保证。这在面试过程中可以和面试官进行探讨,可以让面试官对我们有一个更好的印象。
详细的代码可以上 github 上进行下载。