针对于结点删除,我先介绍剑指offer 18 删除链表的节点。
题目:
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
示例:
输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
使用上面哑结点的技巧,结合模拟法的思考,很自然地得到下面的代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteNode(ListNode* head, int val) {
ListNode* dummyHead = new ListNode(0); // 删除节点需要制造一个新的头结点安排在现有的头结点之前,这是常用手段
dummyHead->next = head;
ListNode* flag = dummyHead;
while (dummyHead->next != nullptr) {
if (dummyHead->next->val == val) {
dummyHead->next = dummyHead->next->next;
break;
}
dummyHead = dummyHead->next;
}
return flag->next;
}
};
这样,我们解决了今天的第一道题目。
第二道题目是力扣83 删除排序链表中的重复元素。我建议先写这题再写今天的每日一题,因为是一个系列的题目,且循序渐进。
题目:
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例:
输入: 1->1->2
输出: 1->2
解题思路还是很清晰的,跳过重复元素即可,下面是代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) { // 链表 本题根据题目要求,跳过重复值的节点即可
ListNode* cur = head;
while (cur != nullptr && cur->next != nullptr) {
if (cur->val == cur->next->val) {
cur->next = cur->next->next;
}
else {
cur = cur->next;
}
}
return head;
}
};
细心的朋友会发现,这题为什么没有用哑结点呀?
因为这题只需要删除重复元素就好,不用把一个元素斩草除根。所以不用设置哑结点。
所以很轻松地,又解决一道题。
最后是今天的题目。和上面的力扣83做比较,发现今天的题目需要把重复的元素斩草除根地删去。显然我们要使用哑结点了。
下面是代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if (head == nullptr) return head; // 特判
ListNode* dummy = new ListNode(0, head); // 设置哑结点
ListNode* cur = dummy;
while (cur->next && cur->next->next) { // 当cur->next与cur->next->next都存在的时候
if (cur->next->val == cur->next->next->val) { // 如果遇到后面两个连续数值相等,那么记录下这个数值
int x = cur->next->val;
while (cur->next && cur->next->val == x) { // 将重复元素删除,这里设置while循环,可以删去多个重复元素
cur->next = cur->next->next; // 在删除元素的过程中,一定要好好理解cur->next的变化,这里很容易出错
// 建议大家在草稿纸上进行推演,你会发现很简单
}
}
else {
cur = cur->next; // 如果没发现重复元素,那么正常推进
}
}
return dummy->next; // 返回头结点
}
};
至此,解决了第三道题目。