【题目】

给定链表的头指针和一个结点指针。在O(1)时间删除该结点。链表结点的定义例如以下:

struct ListNode

{

int        value;

struct ListNode*  next;

};

函数的声明例如以下:

void DeleteNode(ListNode* head,ListNode* node);

【思路】

这是一道广为流传的Google面试题,能有效考察我们的编程基本功,还能考察我们的反应速度,更重要的是,还能考察我们对时间复杂度的理解。

在链表中删除一个结点,最常规的做法是从链表的头结点開始,顺序查找要删除的结点,找到之后再删除。因为须要顺序查找,时间复杂度自然就是O(n) 了。

我们之所以须要从头结点開始查找要删除的结点。是由于我们须要得到要删除的结点的前面一个结点。

我们试着换一种思路。我们能够从给定的结点得到它的下一个结点。

这个时候我们实际删除的是它的下一个结点。由于我们已经得到实际删除的结点的前面一个结点,因此全然是能够实现的。

当然。在删除之前。我们须要须要把给定的结点的下一个结点的数据复制到给定的结点中。此时。时间复杂度为O(1)。

上面的思路另一个问题:假设删除的结点位于链表的尾部,没有下一个结点。怎么办?我们仍然从链表的头结点開始,顺便遍历得到给定结点的前序结点,并完毕删除操作。这个时候时间复杂度是O(n)。

那题目要求我们须要在O(1)时间完毕删除操作,我们的算法是不是不符合要求?实际上,如果链表总共同拥有n个结点,我们的算法在n-1总情况下时间复杂度是O(1)。仅仅有当给定的结点处于链表末尾的时候,时间复杂度为O(n)。那么平均时间复杂度[(n-1)*O(1)+O(n)]/n,仍然为O(1)。

基于前面的分析。我们不难写出以下的代码。

/*********************************
* 日期:2014-10-29
* 作者:SJF0115
* 题目: 给定链表的头指针和一个结点指针,在O(1)时间删除该结点
* 来源:经典面试题
* 总结:
**********************************/
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std; struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
//O(1)时间 删除链表中的节点
void DeleteNode(ListNode** head,ListNode* node){
if(head == NULL || node == NULL){
return;
}
ListNode* p = node->next;
// 删除的不是末尾节点 O(1)
if(p != NULL){
//删除p节点
node->next = p->next;
// 节点p拷贝到node节点
node->next = p->next;
node->val = p->val;
delete p;
p = NULL;
}
// 删除的是末尾节点 O(n)
else{
ListNode* pre = *head;
// 末尾节点
while(pre->next != node){
pre = pre->next;
}
//删除node节点
pre->next = NULL;
delete node;
node = NULL;
}
} int main() {
ListNode* node1 = new ListNode(1);
ListNode* node2 = new ListNode(2);
ListNode* node3 = new ListNode(3);
ListNode* node4 = new ListNode(4);
ListNode* node5 = new ListNode(5); node1->next = node2;
node2->next = node3;
node3->next = node4;
node4->next = node5; //无头结点链表
DeleteNode(&node1,node2); while(node1 != NULL){
printf("%d ",node1->val);
node1 = node1->next;
}
return 0;
}

何海涛:

值得注意的是。为了让代码看起来简洁一些,上面的代码基于两个如果:(1)给定的结点的确在链表中。(2)给定的要删除的结点不是链表的头结点。不考虑第一个如果对代码的鲁棒性是有影响的。

至于第二个如果,当整个列表仅仅有一个结点时,代码会有问题。但这个如果不算非常过分。由于在有些链表的实现中。会创建一个虚拟的链表头,并非一个实际的链表结点。

这样要删除的结点就不可能是链表的头结点了。当然,在面试中,我们能够把这些如果和面试官交流。这样,面试官还是会认为我们考虑问题非常周到的。

[经典面试题]在O(1)时间删除链表结点的更多相关文章

  1. 《剑指offer》面试题13—O(1)时间删除链表结点

    题目:给定单向链表的头指针和某结点指针,实现函数在O(1)时间内删除指定节点. 思路:由于没有要删除结点(j结点)的前一个结点(i结点)指针,通常想法是从头开始遍历找到指定结点的前一个结点(i结点), ...

  2. 【面试题013】在O(1)时间删除链表结点

    [面试题013]在O(1)时间删除链表结点  我们要删除结点i,我们可以把结点i的下一个结点j的内容复制到结点i,然后呢把结点i的指针指向结点j的下一个结点.然后在删除结点j. 1.如果结点i位于链表 ...

  3. 面试题18(一):在O(1)时间删除链表结点

    // 面试题18(一):在O(1)时间删除链表结点 // 题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该 // 结点.链表结点与函数的定义如下: // struct Lis ...

  4. 剑指Offer面试题:12.在O(1)时间删除链表结点

    一.题目:在O(1)时间删除链表结点 题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点. 原文采用的是C/C++,这里采用C#,节点定义如下: public class ...

  5. 【Java】 剑指offer(17) 在O(1)时间删除链表结点

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除 ...

  6. 《剑指offer》第十八题(在O(1)时间删除链表结点)

    // 面试题18(一):在O(1)时间删除链表结点 // 题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该 // 结点. #include <iostream> ...

  7. 第18题:在O(1)时间删除链表结点+删除链表中重复的节点

    题目描述:题目描述在O(1)时间删除链表结点 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点. 考查创新编程能力. 思路: 1.如果从头到尾遍历,时间O(n) 2.如果将待删 ...

  8. 程序员面试题精选100题(33)-在O(1)时间删除链表结点[数据结构]

    作者:何海涛 出处:http://zhedahht.blog.163.com/ 题目:给定链表的头指针和一个结点指针,在O(1)时间删除该结点.链表结点的定义如下: struct ListNode { ...

  9. 剑指Offer:面试题13——在O(1)时间删除链表结点

    问题描述: 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点.链表结点与函数的定义如下: public class ListNode{ int value; ListNode ...

随机推荐

  1. AspNetCore容器化(Docker)部署(一) —— 入门

    一.docker注册安装 Windows Docker Desktop https://www.docker.com/products/docker-desktop Linux Docker CE h ...

  2. Spring-02 Java配置实现IOC

    Java配置 Spring4推荐使用java配置实现IOC Spring boot也推荐采用java配置实现IOC 在实际项目中,一般采用注解配置业务bean,全局配置使用Java配置. Java配置 ...

  3. js 简单制作键盘模拟

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head& ...

  4. Abaqus用户子程序umat的学习

    Abaqus用户子程序umat的学习 说明:在文件中,!后面的内容为注释内容.本文为学习心得,很多注释是自己摸索得到.如有不正确的地方,敬请指正. ! ------------------------ ...

  5. kvm安装图终端界面及形界面安装系统

    1.图形界面安装: qemu-img create -f qcow2 /kvm/os/vm-01.qcow2 16G mkdir -p /kvm/iso cd /kvm/iso 上传事先下载好的镜像文 ...

  6. CSS链接四种状态注意顺序、UI伪类选择器的顺序

    css定义超链接是要有先后顺序的.否则,可能会出现某个或某几个样式不起作用的bug.例如:visited与hover顺序颠倒了,则不能显示hover和active的样式了. 正确的顺序: a:link ...

  7. 【问题探索日志】python 函数优化

    # 事情是这样的,我写的一个程序帧率上不去. 然后发现了一个疑似有问题的地方,如下 def around(x,y): around_dict = {(i,j) for i in range(-1,2) ...

  8. Django 多个字段关联同一外键

    # -*- coding: utf-8 -*- """ Tencent is pleased to support the open source community b ...

  9. 南阳理工 58 最少步数 (DFS)

    描述 这有一个迷宫,有0~8行和0~8列: 1,1,1,1,1,1,1,1,1 1,0,0,1,0,0,1,0,1 1,0,0,1,1,0,0,0,1 1,0,1,0,1,1,0,1,1 1,0,0, ...

  10. 【转】如何在命令行脚本中启动带参数的Windows服务

    我们有一个自己编写的Windows服务,我们希望该服务在启动时可以根据用户输入的参数实现不同的功能. 要实现这样的需求并不是很难,下面这个例子我用来示范如何编写该服务 using System; us ...