面试题17:在O(1)时间删除链表结点
问题描述
给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。
链表结构
public class Node{
int val;
Node next;
public Node(int value,Node next) {
val=value;
next=next;
}
}
问题分析
曾经未碰到这道题之前,删除链表的节点,用的方法非常原始、基础(代码如下),很明显这种原始的方式带来的时间复杂度为O(n)
//从链表中删除index(0~based)位置的元素,返回删除的元素
public E remove(int index) {
if(index<0 || index >=size) {
throw new IllegalArgumentException("remove failed. Illegal index");
}
Node prev = dummyHead;
for(int i=0;i<index;i++) {
prev = prev.next;
}
Node retNode = prev.next;
prev.next = retNode.next;
retNode.next = null;
size--;
return retNode.e;
}
过去刚遇到这道题,半天也没想起来,看到解析后豁然开朗。说明见多识广还是很重要的。
要在O(1)时间删除某结点,可以这样实现:设待删除结点j,j的上一个节点为i,把j的值复制到i,再把i的指针指向j的下一个结点,最后删除j,效果就相当于删除j。
不过注意特殊情况:
(1)当待删除结点i为尾结点时,无下一个结点,则只能从头到尾顺序遍历;
(2)当链表中只有一个结点时(即是头结点,又是尾结点),必须把头结点也设置为null。
问题解答
代码如下:
public class Node{
int val;
Node next;
public Node(int value, Node next) {
val=value;
next=next;
}
}
/**
* 返回值:头结点
* 返回值不可以为void,否则头结点无法删除
* 即:函数中虽然令head=null,但返回到主程序后,
* head还是不变,所以令该函数返回值为Node
*/
public Node deleteNode(Node head, Node pToBeDeleted) {
if(head==null||pToBeDeleted==null)
return head;
if(pToBeDeleted.next != null) { //待删除结点不是尾结点
Node nextNode = pToBeDeleted.next;
pToBeDeleted.val=nextNode.val;
pToBeDeleted.next=nextNode.next;
nextNode=null;
}else if(head == pToBeDeleted) { //只有一个结点(即是尾结点,又是头结点)
pToBeDeleted=null;
head=null;
}else { //链表含多个结点,删除尾结点
Node preNode=head;
while(preNode.next!=pToBeDeleted && preNode!=null) {
preNode=preNode.next;
}
if(preNode==null) {
System.out.println("无法找到待删除结点!");
return head;
}
preNode.next=null;
pToBeDeleted=null;
}
return head;
}
做完这道题,你可能觉得为啥这种方法没有普及开来?其实这种方法有一个致命的缺陷:假设了待删除的结点的确在表中。
原文地址:https://www.cnblogs.com/JefferyChenXiao/p/12246323.html
时间: 2024-10-12 10:09:13