题目建议: 本题最关键是要理解 虚拟头结点的使用技巧,这个对链表题目很重要。
题目链接:https://leetcode.cn/problems/remove-linked-list-elements/
视频讲解:https://www.bilibili.com/video/BV18B4y1s7R9
解题思路:
1.处理头节点:如果头节点的值等于目标值,需要将头节点后移,直到找到一个不等于目标值的节点作为新头节点。
2.遍历链表:使用指针current从新头节点开始遍历链表,检查每个节点的下一个节点(current.next)是否等于目标值。
3.删除匹配节点:如果current.next的值等于目标值,将current.next向current.next.next,跳过匹配的节点。否则,移动current到下一个节点。
代码实现示例
struct ListNode* removeElements(struct ListNode* head, int val) { // 1. 处理头节点 while (head != NULL && head->val == val) { struct ListNode *temp = head; head = head->next; free(temp); } if (head == NULL) return NULL; // 2. 遍历删除中间节点 struct ListNode *current = head; while (current->next != NULL) { if (current->next->val == val) { struct ListNode *temp = current->next; current->next = current->next->next; free(temp); } else { current = current->next; } } return head; }过程中遇到的问题:
1.头节点处理不当,导致内存泄漏或空指针访问
头节点是链表的起点,修改 head 时,必须先保存原节点地址,再移动指针,最后释放,否则会出现内存泄漏或释放错误节点。如果 while 循环的条件写反了(比如 head->val == val && head != NULL ),会直接访问空指针的val, 程序崩溃。
2.处理完头节点后,忘记判断链表是否为空
当链表所有节点的值都等于val(比如示例3 [7,7,7,7] ),头节点循环处理完后,head会变成NULL 。此时直接访问 current->next 等价于 NULL->next ,会触发空指针访问,程序直接崩溃。
3.遍历中间节点时,移动指针的时机错误
假设链表是1→6→6→3,删除第一个6后,链表变成1→6→3。此时current 是1,如果执行current =current->next ,会直接跳到第二个6,导致第二个6永远无法被删除。