一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情
给你一个链表的头节点 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
输出: []
提示:
- 列表中的节点数目在范围
[0, 104]内 1 <= Node.val <= 500 <= val <= 50
解题思路:
这里以 链表 3,2,1,3,1举例,移除 1
移除后的链表
要注意的是: 如果是用C和C++来做题的人,不要忘了还要从内存里删除这两个移除的节点,如果用的是JAVA,就需要手动管理内存
还要说明一下,就算使用C++来做leetcode,如果移除一个节点之后,没有手动在内存中删除这个节点,leetcode依然也是可以通过的,只不过,内存使用的空间大一些而已,但建议依然要养成手动清理内存的习惯
通过上面的图能看出,移除元素的操作,就是让节点next指针直接指向下下一个节点
因为单链表的特殊性,指针只能指向下一个节点,那么这里就会有一个问题,如果删除的是头节点该怎么办呢?
这里可以用链表操作的两种方式
- 直接使用原来的链表进行删除操作
- 设置一个虚节点,再进行删除操作
这里我们先来看第一种方式:直接使用原来的数组进行删除操作
移除头节点和移除其他节点的操作是不一样的,因为链表的其他节点都是需要通过前一个节点来移除元素的,而头节点没有前一个节点
我们只需要将头节点向后移一位,就完成了移除头节点的这个操作
这里别忘了将移除的节点从内存中删除
这里可以发现,在单链表里移除头节点和移除其他节点的操作还是不一样的,我们在写代码的时候,需要单独写一个逻辑处理移除头节点的情况
写完第一个方式,我们再来看第二种方式:设置一个虚节点,再进行删除操作
我们来看看添加一个虚节点后,如何移除节点
这里还是用链表 1,2,6,3,5 移除1 进行操作
可以看到,添加了虚节点后,删除的操作就跟删除其他节点的操作一样了
最后在返回头节点时,要 return head.next,这才是新的头节点
代码: (Java实现)
不添虚节点
public ListNode removeElements(ListNode head, int val) {
//判断删除的节点是否为头节点,如果是,就把头节点移动到下一位
if (head != null && head.val == val) {
head = head.next;
}
if (head == null) {
return head;
}
ListNode per = head;
ListNode cur = head.next;
while (cur != null) {
if (cur.val == val) {
per.next = cur.next;
}else {
per = cur;
}
cur = cur.next;
}
return head;
}
复杂度分析:
- 时间复杂度:O(n)
- 空间复杂度:O(1)
提交结果:
添加虚节点
public ListNode removeElements(ListNode head, int val) {
if (head == null) {
return null;
}
//创建虚节点
ListNode one_head = new ListNode(-1,head);
//创建虚节点
ListNode per = one_head;
//实际头节点
ListNode cur = head;
while (cur != null) {
if (cur.val == val) {
per.next = cur.next;
}else {
per = cur;
}
cur = cur.next;
}
return one_head.next;
}
复杂度分析:
- 时间复杂度:O(n)
- 空间复杂度:O(1)