题目一:在O(1)时间内删除链表节点
给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点,链表节点与函数的定义如下:
struct ListNode
{
int m_nValue;
ListNode* m_pnext;
};
void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted);
常规做法是从链表的头结点开始,顺序遍历查找要删除的节点,并在链表中删除该节点,但此时的时间复杂度为O(n),这种做法默认的前提是先要找到要删除节点的前一个节点
推荐做法是对n-1个非尾节点而言,可以在O(1)时间内把下一个节点的内存复制覆盖要删除的节点,并删除下一个节点;对于尾节点而言,仍然需要顺序查找,时间复杂度为O(n)。总的时间复杂度为
[(n-1)*O()+O()]/n=O(1),符合要求。
void DeleteNode(ListNode**pListHead, ListNode* pToBeDeleted)
{
if(!pListHead || !pToBeDeleted)
return;
//要删除的节点不是尾节点
if(pToBeDeleted->m_pNext != NULL)
{
ListNode* pNext = pToBeDeleted -> m_pNext;
pToBeDeleted -> m_nValue = pNext -> m_nValue;
pToBeDeleted -> m_pNext = pNext -> m_pNext;
delete pNext;
pNext = NULL;
} else if(*pListHead == pToBeDeleted)//链表只有一个节点,删除头结点(也是尾节点)
{
delete pToBeDeleted;
pToBeDeleted = NULL;
*pListHead = NULL;
} else {//链表中有多个节点,删除尾节点
ListNode* pNode = *pListHead;
while(pNode -> m_pNext != pToBeDeleted)
{
pNode = pNode -> m_pNext;
}
pNode -> m_pNext = NULL;
delete pToBeDeleted;
pToBeDeleted = NULL;
}
}
所以,要删除一个节点时,并不一定要删除这个节点本身,可以先把下一个节点的内容复制出来覆盖被删除节点的内容,然后把下一个节点删除。
题目二:删除排序链表中重复节点,重复节点不保留
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
牛客网上的大佬解答:
1.递归
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if (pHead==NULL)
return NULL;
if (pHead!=NULL && pHead->next==NULL)
return pHead;
ListNode* current;
if ( pHead->next->val==pHead->val){
current=pHead->next->next;
while (current != NULL && current->val==pHead->val)
current=current->next;
return deleteDuplication(current);
}
else {
current=pHead->next;
pHead->next=deleteDuplication(current);
return pHead;
}
}
};
2.思路清晰
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if( pHead == NULL ) return pHead;
ListNode *pre = NULL; //指向前面最晚访问过的不重复结点
ListNode *p = pHead; //指向当前处理的结点
ListNode *q = NULL; //指向当前处理结点后面结点
while( p != NULL )
{
//当前结点p,(其实是p指向当前结点),与它下一个结点p->next的val相同,说明要删掉有这个val的所有结点
if( p->next != NULL && p->next->val == p->val )
{
q = p->next;
//找到q,它指向最后一个与p val相同的结点,那p 到 q (包含) 都是要删除的
while( q != NULL && q->next != NULL && q->next->val == p->val )
{
q = q->next;
}
//如果p指向链表中第一个元素,p -> ... -> q ->... , 要删除p到q, 将指向链表第一个元素的指针pHead指向q->next。
if( p == pHead )
{
pHead = q->next;
}
else//如果p不指向链表中第一个元素,pre -> p ->...->q ->... ,要删除p到q,即pre->next = q->next
{
pre->next = q->next;
}
//当前处理的p要向链表尾部移动
p = q->next;
}
else
{
pre = p;
p = p->next;
}
}
return pHead;
}
};