【剑指offer 18. 删除链表的节点】
剑指offer 18. 删除链表的节点
题目
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。
题目链接:https://leetcode.cn/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/
题解
解法1:双指针
解法分析
- 先判断头指针是否为空,为空返回
- 判断头指针指向val是否为待查找值,是则返回head->next
- 使用p表示当前指向的节点,使用front保存当前节点p的前一个节点,为了方便后续修改勾连关系
- 循环直到p->val==val时修改front指向的next绕过p,指向p后面的节点
边界条件、特殊值分析、测试、注意事项
- 需要小心防范头指针为空的情况
复杂度分析
时间复杂度 O(n),最坏情况需要遍历扫描整个链表
空间复杂度 O(1),只使用了两个辅助变量
代码
class Solution {
public:
ListNode* deleteNode(ListNode* head, int val) {
if (head == NULL) return head;
if (head->val == val) return head->next;
ListNode* p=head;
ListNode* front = p;
while (p != NULL && p-> val != val) {
front=p;
p=p->next;
}
if(p==NULL){
return head;
}
front->next=p->next;
return head;
}
};
可能存在的问题
- 使用双指针还是有点空间上的不必要消耗的,考虑使用单指针
解法2:单指针
解法分析
- 先判断头指针是否为空,为空返回
- 判断头指针指向val是否为待查找值,是则返回head->next
- 使用cur表示当前指向的节点,永远检查next指针与next指针域下的val,以此来避免多一个front指针,即cur相当于前面双指针的front指针,只不过使用front->next取代了p
边界条件、特殊值分析、测试、注意事项
- 需要小心防范头指针为空的情况
复杂度分析
时间复杂度 O(n),最坏情况需要遍历扫描整个链表
空间复杂度 O(1),只使用了两个辅助变量
代码
class Solution {
public:
ListNode* deleteNode(ListNode* head, int val) {
if (head == NULL) return head;
if (head->val == val) return head->next;
ListNode* cur = head;
while (cur->next != NULL) {
if (cur->next->val == val) {
cur->next = cur->next->next;
return head;
}
curr = cur->next;
}
return head;
}
};
可能存在的问题
- 暂无
更多解法
- 使用递归
- 当前节点为空时退出
- 为待查值时向被调用函数返回next指针
- 使用栈
- 将所有值依次压栈,直到遇到待查值或者NULL
- 遇到待查值,则将栈中元素重新组织为链表,并将待查值->next勾连到新组成的链表后方
- 遇到NULL,重组栈中值为链表
- 使用虚拟头节点
- 通过使用虚拟头节点,进一步统一上述单指针解法与双指针解法中的头部需要额外判断的问题