输入:链表 head,整数 val。
要求:删除链表中所有值等于 val 的节点,返回新链表的头节点。
输出:删除后链表的头节点。
思路一:直接遍历(原地修改)
- 使用一个虚拟头结点
dummy,使其next指向原始head。这样做的好处是,即使原始头节点需要被删除,我们也能统一处理,无需特殊判断。 - 定义一个指针
cur从dummy开始遍历。 - 循环检查
cur->next节点:- 如果
cur->next的值等于val,则执行删除操作:cur->next = cur->next->next,直接跳过该节点。 - 如果值不等于
val,则正常后移指针:cur = cur->next。
- 如果
- 遍历结束后,返回
dummy->next即可。
复杂度:
- 时间复杂度:O(n),n为链表长度。
- 空间复杂度:O(1)。
思路二:尾插法(构建新链表)
- 新建一个虚拟头结点
dummy用于构建新链表,并用一个指针cur指向新链表的尾部,初始时cur = dummy。 - 遍历原始链表(用
head指针):- 如果当前
head节点的值等于val,则跳过该节点,仅移动head = head->next。 - 如果值不等于
val,则将其“摘下”并链接到新链表的尾部:cur->next = head;// 链接节点head = head->next;// 原链表指针后移cur = cur->next;// 新链表尾指针后移cur->next = NULL;// 关键:断开与原链表后续节点的连接,否则会把不需要的节点也带过来。
- 如果当前
- 遍历结束后,返回
dummy->next。
复杂度:
- 时间复杂度:O(n)。
- 空间复杂度:O(1),因为我们只是重新组织了原有节点,没有创建新节点。
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
// 思路一:直接遍历(原地修改)
// ListNode* dummy = new ListNode(0, head);
// ListNode* cur = dummy;
// while (cur->next) {
// if (cur->next->val == val) {
// ListNode* del = cur->next;
// cur->next = cur->next->next;
// delete del; // 在 LeetCode 环境中可以不写 delete
// } else {
// cur = cur->next;
// }
// }
// return dummy->next;
// 思路二:尾插法(构建新链表)
ListNode* dummy = new ListNode(0, NULL);
ListNode* cur = dummy;
while (head) {
if (head->val == val) {
// 如果是目标值,直接跳过,原链表指针后移
head = head->next;
}
else {
// 如果不是目标值,接到新链表尾部
cur->next = head;
head = head->next;
cur = cur->next;
cur->next = NULL; // 断开链接
}
}
return dummy->next;
}
};
515

被折叠的 条评论
为什么被折叠?



