题目
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点 。
解题思路
思路一
用迭代的思想遍历,分为带虚拟头节点的迭代和不带虚拟头节点的迭代
不带虚拟头节点的迭代处理较为麻烦,要考虑头节点为空的情况并且更新头节点,以下是代码
//迭代实现 删除头结点时另做考虑(由于头结点没有前一个结点)
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* removeElements(ListNode* head, int val)
{
while(nullptr != head && val == head->val)
{
ListNode* imp = head;
head = head->next;
delete imp;
}
if (nullptr == head)
return head;
ListNode* pNode = head;
while (nullptr != pNode->next)
{
if (val == pNode->next->val)
{
ListNode* imp = pNode->next;
pNode->next = imp->next;
delete imp;
}
else
{
pNode = pNode->next;
}
}
return head;
}
};
而带虚拟头节点的在删除头节点的时候就不用另作考虑,以下是代码
//创建了虚拟头指针的迭代 无需考虑头指针情况
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* removeElements(ListNode* head, int val)
{
ListNode* dummyNode = new ListNode(-1, head);
ListNode* pNode = dummyNode;
while (pNode->next != nullptr)
{
if (pNode->next->val == val)
{
ListNode* imp = pNode->next;
pNode->next = imp->next;
delete imp;
}
else
{
pNode = pNode->next;
}
}
return dummyNode->next;
}
};
时间复杂度:O(n)
空间复杂度:O(1)
思路2
用递归的思路,代码简洁
//递归实现
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* removeElements(ListNode* head, int val)
{
if (head == nullptr)
{
return head;
}
head->next = removeElements(head->next, val);
return head->val == val ? head->next : head;
}
};
时间复杂度:O(n)递归过程中需要遍历链表一次。
空间复杂度:O(n)空间复杂度主要取决于递归调用栈,最多不会超过 n 层
总结
这类题目平时用迭代的思路比较多,思路二的递归代码更简洁,但是可以发现其空间复杂度是高于递归的。