给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。
4月份找实习时滴滴视频面,就是出的这道题目,当时舍友提示说覆盖即可。
分析:
- 一般的单链表中删除节点,遍历该链表,发现下一个是待删点,则删除。从头查找复杂度是O(n),因为我们需要找到待删点的前一个点。
- 题目给定该结点的指针,要删除该结点,直接删则链表就断了。
- 链表利用指针连接起来,非常灵活。可以把待删节点的下一个节点复制给待删点,然后删掉后面的点。就可以达到题目要求的结果。
注意:
- 此题思路清晰,需要关注几个边界情况。如待删点为尾结点时,则必须从头开始遍历得到次尾结点。
- 如果链表中只有一个结点,删除该结点,则需要把头指针置空。
- 其余则属于正常情况的删除即可。
代码:
// offer-13-O(1)ListDelete.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
// 链表结点定义
struct ListNode{
int value;
ListNode * pnext;
};
// 删除某给定的结点
void DeleteNode(ListNode ** pListHead, ListNode * pToBedelete)
{
// 指针判断
if(!pListHead || !pToBedelete)
return;
// 如果不是尾结点,属于正常中间的某结点
if(pToBedelete->pnext != nullptr)
{
ListNode * ptmp = pToBedelete->pnext;
pToBedelete->value = ptmp->value;
pToBedelete->pnext = ptmp->pnext;
delete ptmp;
ptmp = nullptr;
}
// 如果是尾结点,判断是不是只有一个结点
else if(*pListHead == pToBedelete)
{
delete pToBedelete;
pToBedelete = nullptr;
*pListHead = nullptr;
}
// 如果是尾结点且链表有多个结点,需从头遍历
else
{
ListNode * ptmp = *pListHead;
while(ptmp->pnext != pToBedelete)
{
ptmp = ptmp->pnext;
}
ptmp->pnext = nullptr;
delete pToBedelete;
pToBedelete = nullptr;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
对于n-1个非尾结点而言,可以在O(1)时间把下一个结点的内存复制到需要删除的结点,并删除下一个结点;
对于尾结点而言,仍然需要顺序查找,时间复杂度是O(n)。总的平均时间复杂度是 [(n−1)∗O(1)+O(n)]/n=O(1) ,符合要求。
但是它还基于一个假设:要删除的结点的确在链表中。我们需要O(n)的时间才可以判断链表中是否包含某个结点,因此确保工作交给了函数的调用者。