三指针的解法
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(nullptr) {}
};
class Solution {
public:
ListNode* deleteNode(ListNode* head, int val) {
cur = head;
while (cur != nullptr) {
// 目标值和待删除的值是否相等
if (val == cur->val) {
// 待删除结点是否是头结点
if (cur == head) {
cur = cur->next;
return cur;
}
// 不是头节点,目标结点的前驱结点指向后继结点
pre->next = nex;
return head;
}
// 目标结点和待删除结点不相等,保存待删除结点的前驱结点和后继结点
nex = cur->next;
pre = cur;
cur = nex;
nex = nex->next;
}
// 目标值不存在链表中,直接返回整个链表
return cur;
}
private:
ListNode *pre = nullptr;
ListNode *cur = nullptr;
ListNode *nex = nullptr;
};
思路:
本题整体思路是遍历链表,查找要删除的目标结点。这里设置三个指针pre,cur,nex,pre指向待删除结点的伪前驱结点,nex指向待删除结点的后继结点,cur指向当前待删除结点(待删除的意思是是否是目标结点)。首先比较目标值和待删除的值是否相等,若相等,则进一步判断待删除的结点是否是头结点,若是头结点,则cur指针直接指向next结点返回即可。若不是头结点,则pre指针的next指针指向nex返回头结点即可。若不相等,则cur的next指向nex结点,pre指针指向cur结点,cur指向nex结点,nex指向nex的next结点,目的是为了保存待删除结点的前驱和后继结点。若目标结点不存在于链表中,则返回整个链表。
最好时间复杂度O(1),最坏时间复杂度O(n),平均时间复杂度O(n/2),空间复杂度O(1)
哑结点的解法
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(nullptr) {}
};
class Solution {
public:
ListNode* deleteNode(ListNode* head, int val) {
dummy->next = head;
if(!dummy->next)return head;
cur = head;
pre = dummy;
while(cur!=nullptr){
if(cur->val==val){
pre->next = cur->next;
cur = cur->next;
}else{
pre = cur;
cur = cur->next;
}
}
return dummy->next;
}
private:
// dummy不能为Null,不然报underflow异常
ListNode *dummy = new ListNode(-1);
ListNode *cur = nullptr;
// ListNode *nex = nullptr;
ListNode *pre = nullptr;
};