[经典面试题]在O(1)时间删除链表结点
【题目】
给定链表的头指针和一个结点指针。在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)时间删除链表结点的更多相关文章
- 《剑指offer》面试题13—O(1)时间删除链表结点
题目:给定单向链表的头指针和某结点指针,实现函数在O(1)时间内删除指定节点. 思路:由于没有要删除结点(j结点)的前一个结点(i结点)指针,通常想法是从头开始遍历找到指定结点的前一个结点(i结点), ...
- 【面试题013】在O(1)时间删除链表结点
[面试题013]在O(1)时间删除链表结点 我们要删除结点i,我们可以把结点i的下一个结点j的内容复制到结点i,然后呢把结点i的指针指向结点j的下一个结点.然后在删除结点j. 1.如果结点i位于链表 ...
- 面试题18(一):在O(1)时间删除链表结点
// 面试题18(一):在O(1)时间删除链表结点 // 题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该 // 结点.链表结点与函数的定义如下: // struct Lis ...
- 剑指Offer面试题:12.在O(1)时间删除链表结点
一.题目:在O(1)时间删除链表结点 题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点. 原文采用的是C/C++,这里采用C#,节点定义如下: public class ...
- 【Java】 剑指offer(17) 在O(1)时间删除链表结点
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除 ...
- 《剑指offer》第十八题(在O(1)时间删除链表结点)
// 面试题18(一):在O(1)时间删除链表结点 // 题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该 // 结点. #include <iostream> ...
- 第18题:在O(1)时间删除链表结点+删除链表中重复的节点
题目描述:题目描述在O(1)时间删除链表结点 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点. 考查创新编程能力. 思路: 1.如果从头到尾遍历,时间O(n) 2.如果将待删 ...
- 程序员面试题精选100题(33)-在O(1)时间删除链表结点[数据结构]
作者:何海涛 出处:http://zhedahht.blog.163.com/ 题目:给定链表的头指针和一个结点指针,在O(1)时间删除该结点.链表结点的定义如下: struct ListNode { ...
- 剑指Offer:面试题13——在O(1)时间删除链表结点
问题描述: 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点.链表结点与函数的定义如下: public class ListNode{ int value; ListNode ...
随机推荐
- CSS3--- 颜色
1.RGB是一种色彩标准,是由红(R).绿(G).蓝(B)的变化以及相互叠加来得到各式各样的颜色.RGBA是在RGB的基础上增加了控制alpha透明度的参数. 语法:color:rgba(R,G,B, ...
- 第一章:systemverilog简介
1.为何要学systemverilog ..... 2.systemverilog起源 ..... 3.systemverilog标准历程 systemverilog3.0 for 综合 system ...
- MySQL autocommit 和 start transaction
autocommit 和 start transaction 都是事务相关的命令.类似MyISAM的mysql引擎就不支持. autocommit 默认是ON状态,即sql语句是自动提交的 show ...
- PCB线宽与电流计算器--在线计算
http://eda365.com/article-12-1.html 计算线宽与载流量的关系,方便设计:单个人建议在有限的空间尽量将大电流线路加宽.
- Spring核心技术(九)——Spring管理的组件和Classpath扫描
Spring管理的组件和Classpath的扫描 在前文描述中使用到的Spring中的Bean的定义,都是通过指定的XML来配置的.而前文中描述的注解的解析则是在源代码级别来提供配置元数据的.在那些例 ...
- UI进阶 即时通讯之XMPP环境搭建
内容中包含 base64string 图片造成字符过多,拒绝显示
- python3--shelve 模块
shelve模块是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式 import shelve d = shelve.open('shelve_t ...
- NYOJ-676小明的求助,快速幂求模,快速幂核心代码;
小明的求助 时间限制:2000 ms | 内存限制:65535 KB 难度:2 描述 小明对数学很有兴趣,今天老师出了道作业题,让他求整数N的后M位,他瞬间感觉老师在作弄他,因为这是so easy ...
- [luoguP2564][SCOI2009]生日礼物(队列)
传送门 当然可以用队列来搞啦. # include <iostream> # include <cstdio> # include <cstring> # incl ...
- 单源最短路径 Bellman_ford 和 dijkstra
首先两个算法都是常用于 求单源最短路径 关键部分就在于松弛操作 实际上就是dp的感觉 if (dist[e.to] > dist[v] + e.cost) { dist[e.to] = dist ...