题目1:在O(1)的时间内删除链表节点
给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点。
问题解析:
链表节点与函数的定义如下:
struct ListNode{
int value;
ListNode* next;
ListNode(int val): value(val), next(nullptr) {}
};
链接:
剑指Offer(第2版):P119
思路标签:
数据结构:链表
后节点替换指定节点。
解答:
1. C++
- 一般的,要从单向链表中删除一个指定的节点,我们需要知道其前一节点和后一节点,后一节点由其next属性很容易得知,但是如果要知道其前一节点需要对链表进行遍历,遍历的时间复杂度就是O(n);
- 但是换一种思路我们也可以不需要知道删除节点的前一个节点:用后一节点完全复制覆盖删除节点,再删除后一节点;
- 注意,如果指定删除节点位于节点的尾部,没有可以用来替换的节点,那么我们就还是需要从头到尾遍链表,寻找其前一个节点;
- 同时,注意链表中只有一个元素的情况,需要将头节点设置为nullptr。
void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted) {
if (!pListHead || !pToBeDeleted)
return;
//要删除的节点不是尾节点
if (pToBeDeleted->next != nullptr) {
ListNode* pNext = pToBeDeleted->next;
pToBeDeleted->value = pNext->value;
pToBeDeleted->next = pNext->next;
delete pNext;
pNext = nullptr;
}
//只有一个节点的情况
else if (*pListHead == pToBeDeleted) {
delete pToBeDeleted;
pToBeDeleted = nullptr;
*pListHead = nullptr;
}
//要删除的节点是尾节点
else {
ListNode* pNode = *pListHead;
while (pNode->next != pToBeDeleted) {
pNode = pNode->next;
}
pNode->next = nullptr;
delete pToBeDeleted;
pToBeDeleted = nullptr;
}
}
- 注意头结点指针是指向指针的指针。
题目2:删除链表中重复的节点
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。
Example:
例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
链接:
剑指Offer(第2版):P122
思路标签:
数据结构:链表
解答:
1. C++
- 因为要删除重复的节点,所以需要保存重复节点的前一个节点;
- 需要设置重复的标志。
class Solution {
public:
ListNode* deleteDuplication(ListNode** pHead)
{
if (pHead == nullptr || *pHead == nullptr) return;
ListNode* pPreNode = nullptr;
ListNode* pNode = *pHead;
while (pNode != nullptr) {
ListNode* pNext = pNode->next;
bool needDelete = false;
if (pNext != nullptr && pNext->val == pNode->val)
needDelete = true;
if (!needDelete) {
pPreNode = pNode;
pNode = pNode->next;
}
else {
int value = pNode->val;
ListNode* pToBeDeleted = pNode;
while (pToBeDeleted != nullptr && pToBeDeleted->val == value) {
pNext = pToBeDeleted->next;
delete pToBeDeleted;
pToBeDeleted = pNext;
}
pNode = pNext;
if (pPreNode == nullptr)
*pHead = pNode;
else
pPreNode->next = pNode;
}
}
}
};