一、双指针法:
1.添头法:
需要想清楚定义几个指针或节点用于保存,并新建一个节点做头。
class Solution {
public:
// 共四个指针要用变量存储:
// 一、返回值的头dummy;
// 二、删除起始处的上一个节点pre
// 三、删除起始处p1
// 四、删除终止处p2
ListNode* deleteDuplicates(ListNode* head) {
ListNode* dummy = new ListNode(250, head); // 虚增的头,解决链表开始即重复的问题
ListNode* pre = dummy;
ListNode* p1 = head;
while (p1 != nullptr) {
ListNode* p2 = p1 -> next;
while ((p2 != nullptr) && (p1 -> val == p2 -> val)) {
p2 = p2 -> next;
}
// 至此,p2指向重复节点的后面一个节点
if (p2 != p1 -> next) { //有重复
pre -> next = p2; // 出现连续需要删除的多段节点时,刷新pre->next
} else {
pre = p1;
}
p1 = p2;
}
return dummy -> next;
}
};
2.子函数法:
能拆分出一个完整返回下一个非重复节点的功能即可。
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* realHead = brige(head); // 链表的头,首个非重复节点
ListNode* hang(realHead); // 需要挂起,直至找到匹配的节点
while (hang != nullptr) {
hang->next = brige(hang->next);
hang = hang->next;
}
return realHead;
}
private:
// INPUT: 某链表的head
// OUTPUT: 返回第一个重复节点后的链表指针或本身
ListNode* brige(ListNode* head) {
ListNode* waiter(head);
ListNode* explorer(nullptr);
while (waiter != nullptr) {
explorer = waiter->next;
while ((explorer != nullptr) && (explorer->val == waiter->val)) {
explorer = explorer->next;
}
if (explorer == waiter->next) {
return waiter;
} else {
waiter = explorer;
}
}
return nullptr;
}
};
二、递归法:
递归法一般思路清晰且代码量少,容易实现,但可能栈溢出,视问题情况而定。
本题共分四种情况:
一、→nullptr
二、→①→①→...→
三、→①→nullptr
四、→①→②→...→
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if (head == nullptr) { // 第一种情况
return head;
}
if ((head->next != nullptr) && (head->val == head->next->val)) { // 第二种情况
while ((head->next != nullptr) && (head->val == head->next->val)) {
head = head->next;
}
return deleteDuplicates(head->next); // 不建立连接关系,将删除重复后的节点作为头节点
} else { // 第三、四种情况
head->next = deleteDuplicates(head->next); // 建立连接关系
return head;
}
}
};