题目:
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
示例 2:
输入:head = [], val = 1
输出:[]
示例 3:
输入:head = [7,7,7,7], val = 7
输出:[]
思路:
-
不需要删除头节点
这种情况下的移除操作,就是让节点next指针直接指向下下一个节点就可以了。 -
需要删除头节点
因为单链表的特殊性,只能指向下一个节点,刚刚删除的是链表的中第二个,和第四个节点,那么如果删除的是头结点又该怎么办呢?
这里就涉及如下链表操作的两种方式:
方法1:直接使用原来的链表来进行删除操作。
方法2:设置一个虚拟头结点在进行删除操作。方法1
只要将头结点向后移动一位就可以。
依然别忘将原头结点从内存中删掉。
在单链表中移除头结点和移除其他节点的操作方式不一样,需要单独写一段逻辑来处理移除头结点的情况。方法2
设置一个虚拟头结点,这样原链表的所有节点就都可以按照统一的方式进行移除了。
代码:
// 方法1
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
// 删除头结点
while (head != NULL && head->val == val) { // 注意这里不是if
ListNode* tmp = head;
head = head->next;
delete tmp;
}
// 删除非头结点
ListNode* cur = head;
while (cur != NULL && cur->next!= NULL) {
if (cur->next->val == val) {
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
} else {
cur = cur->next;
}
}
return head;
}
};
// 方法2
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
// 设置一个虚拟头节点,保证头节点操作和其他节点操作一样
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* cur = dummyHead;
// 反复执行直到尾节点
while(cur->next != NULL)
{
// 满足条件则删除节点
if(cur->next->val == val)
{
ListNode* temp = cur->next; // 暂存要删除的节点
cur->next = cur->next->next; // 将当前节点的next指向下下个节点
delete temp; // 删除节点释放内存
}
// 不满足条件,将当前遍历节点向后移一位
else
{
cur = cur->next;
}
}
head = dummyHead->next;
delete dummyHead;
return head;
}
};
总结:
时间复杂度: O(n)
空间复杂度: O(1)
在单链表中移除头结点和移除其他节点的操作方式不一样。可以设置一个虚拟头结点,这样原链表的所有节点就都可以按照统一的方式进行移除了。