[经典面试题]在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 ...
随机推荐
- ubuntu下操作Hadoop、hdfs、hbase、zookeeper时产生的一些问题及解决办法
2019/05/29 1.在终端输入jps时,没有显示Hdfs的DataNode 在文件夹中分别找到DataNode 和Namenode的version,将Datanode的version改为与nam ...
- Socket通信时服务端无响应,客户端超时设置
背景:在写一个客户端的socket程序,服务端没有返回消息,客户端一直在等待. 目标:我需要设置一个时间,如果超过这个时间客户端自动断开连接.最好是在服务端实现,客户端对我来说不可控.
- hdu5279 YJC plays Minecraft
题目描述 题解: 岛屿之间的边砍/不砍情况有$2^n$种, 但是需要剪掉所有的岛上都首尾相连的情况. $dp$一下对于完全图没有限制($f$)/有限制($g$)的情况数. 方程:$$f[i]=\sum ...
- 微信小程序wx.request请求服务器json数据并渲染到页面
[原文出自]: https://blog.csdn.net/weixin_39927850/article/details/79766259 微信小程序的数据总不能写死吧,肯定是要结合数据库来做数据更 ...
- 关于U盘安装ubuntu-18.04安装时候出现的grub-efi-amd64-signed的问题。
关于这个问题,首先我们要查看一下我们电脑的主板设置中U盘启动的类型是什么,是UEFI还是legacy? 对于如果是UEFI那么给ubuntu分区的时候不用设置/boot分区,设置efi系统分区:如果是 ...
- memcached内存分配
Memcached默认情况下采用了名为Slab Allocator的机制分配.管理内存,最大单个存储对象大小为1M. page:分配给slab的最小内存空间,默认为1M,可以在启动时通过-l参数修改 ...
- POJ 3258 River Hopscotch (二分法)
Description Every year the cows hold an event featuring a peculiar version of hopscotch that involve ...
- Java学习关于随机数工具类--Random类
Random类是伪随机数生成器.之所以称为伪随机数(pseudorandom),是因为它们只是简单的均匀分布序列.Random类定义了以下构造函数: Random() Random(long seed ...
- AI学习笔记(02)
AI学习笔记 第一个黑箭头是用于挑选物体和移 动物体.在绘图是选中一个物体,就可以将它自由的移动.和其他的绘图软件相同当你选 中物体的时候物体周围就会出现八个方形的控制点,你可以通过这些控制点对物 ...
- 一些简单的JavaScript的方法
<script type="text/javascript"> //js跳转 function UserMouserDown() { confirm('你确定要删除吗? ...