剑指Offer之在O(1)时间删除链表节点
题目描述
给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间删除该节点。
解题思路
在单向链表中删除一个节点,最常规的做法无疑是从链表的头结点开始,顺序的遍历查找要删除的节点,并在链表中删除该节点。这种思路由于需要顺序查找,时间复杂度自然就是$O(n)$了。
之所以需要从头开始查找,是因为我们需要得到将删除的节点的前面一个节点。在单向链表中,节点中没有指向前一个节点的指针,所以只好从链表的头结点开始顺序查找。那是不是一定需要得到被删除的节点的前一个节点呢?答案是否定的。我们可以很方便地得到要删除的节点的下一个节点。如果我们把下一个节点的内容复制到需要删除的节点上覆盖原有的内容,再把下一个节点删除,这样就相当于把当前需要删除的节点删除了。具体操作如下图所示:
上述思路需要注意两个问题:1、如果要删除的节点位于链表的尾部,那么它就没有下一个节点,我们仍然需要从链表的头结点开始,顺序的遍历得到该节点的前序节点,并完成删除操作。2、如果链表只有一个节点,而我们又要删除链表的头结点(也是尾节点),此时我们在删除节点后,还需要把链表的头结点设置为NULL。
Java代码如下:
package com.swordOffer.deleteNodeInList10; /** * Created by Feng on 2017/5/7. * 给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间删除该节点。 */ public class DeleteNodeInList { public static void main(String[] args) { ListNode node1 = new ListNode(1); ListNode node2 = new ListNode(2); ListNode node3 = new ListNode(3); node1.next = node2; node2.next = node3; deleteNodeInList(node1, node2); while (node1 != null) { System.out.print(node1.val + " "); node1 = node1.next; } } public static void deleteNodeInList(ListNode pHead, ListNode deleteNode) { //判断节点是否为空 if (pHead == null || deleteNode == null) { return; } //链表有多个节点,要删除的不是尾节点:O(1)时间 if (deleteNode.next != null) { ListNode pNext = deleteNode.next; deleteNode.val = pNext.val; deleteNode.next = pNext.next; } else if (pHead == deleteNode) { //链表只有一个结点,删除头结点(也是尾结点):O(1)时间 deleteNode = null; pHead = null; } else { //链表有多个节点,要删除的是尾节点:O(n)时间 ListNode pNode = pHead; while (pNode.next != deleteNode) { pNode = pNode.next; } pNode.next = null; deleteNode = null; } } } class ListNode { int val; ListNode next; ListNode(int x) { val = x; next = null; } }