0
点赞
收藏
分享

微信扫一扫

链表题目:移除链表元素

早安地球 2022-02-14 阅读 62
链表

文章目录

题目

标题和出处

标题:移除链表元素

出处:203. 移除链表元素

难度

3 级

题目描述

要求

给你一个链表的头结点 head \texttt{head} head 和一个整数 val \texttt{val} val,请你删除链表中所有满足 Node.val = val \texttt{Node.val} = \texttt{val} Node.val=val 的结点,并返回新的头结点

示例

示例 1:

示例 1

输入: head   =   [1,2,6,3,4,5,6],   val   =   6 \texttt{head = [1,2,6,3,4,5,6], val = 6} head = [1,2,6,3,4,5,6], val = 6
输出: [1,2,3,4,5] \texttt{[1,2,3,4,5]} [1,2,3,4,5]

示例 2:

输入: head   =   [],   val   =   1 \texttt{head = [], val = 1} head = [], val = 1
输出: [] \texttt{[]} []

示例 3:

输入: head   =   [7,7,7,7],   val   =   7 \texttt{head = [7,7,7,7], val = 7} head = [7,7,7,7], val = 7
输出: [] \texttt{[]} []

数据范围

  • 列表中的结点数目在范围 [0,   10 4 ] \texttt{[0, 10}^\texttt{4}\texttt{]} [0, 104]
  • 1 ≤ Node.val ≤ 50 \texttt{1} \le \texttt{Node.val} \le \texttt{50} 1Node.val50
  • 0 ≤ val ≤ 50 \texttt{0} \le \texttt{val} \le \texttt{50} 0val50

解法一

思路和算法

根据链表的特点,可以使用递归的做法移除链表元素。递归做法可以分成两步:

  1. 对除了头结点以外的结点进行移除链表元素操作,删除结点值等于 val \textit{val} val 的全部结点;

  2. 判断头结点的值是否等于 val \textit{val} val,决定是否要删除头结点。

递归的终止条件是空链表。当链表为空时,不包含任何结点,因此直接返回空链表。

当链表非空时,递归地移除链表元素,然后根据头结点的值是否等于 val \textit{val} val 决定是否要删除头结点。

代码

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if (head == null) {
            return head;
        }
        head.next = removeElements(head.next, val);
        return head.val == val ? head.next : head;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是链表的长度。需要遍历链表一次,对于每个要删除的结点,删除一个结点的时间是 O ( 1 ) O(1) O(1)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是链表的长度。空间复杂度主要取决于递归调用栈的深度,递归调用栈最多不会超过 n n n 层。

解法二

思路和算法

删除一个结点的做法是,定位到待删除结点的前一个结点,将前一个结点的 next \textit{next} next 指针指向待删除结点的后一个结点。假设待删除的结点是 curr \textit{curr} curr,该结点的前一个结点是 prev \textit{prev} prev,则在删除结点之前有 prev . next = curr \textit{prev}.\textit{next} = \textit{curr} prev.next=curr,删除结点时,将 prev . next \textit{prev}.\textit{next} prev.next 指向 curr . next \textit{curr}.\textit{next} curr.next,即完成了将结点 curr \textit{curr} curr 删除的操作。

由于头结点可能是待删除的结点,因此创建哑结点 dummyHead \textit{dummyHead} dummyHead,令 dummyHead . next = head \textit{dummyHead}.\textit{next} = \textit{head} dummyHead.next=head。从 dummyHead \textit{dummyHead} dummyHead 开始遍历链表,用 temp \textit{temp} temp 表示遍历到的结点,进行如下操作:

  • 如果 temp . next . val \textit{temp}.\textit{next}.\textit{val} temp.next.val 等于 val \textit{val} val,则将 temp . next \textit{temp}.\textit{next} temp.next 指向 temp . next . next \textit{temp}.\textit{next}.\textit{next} temp.next.next

  • 否则, temp . next \textit{temp}.\textit{next} temp.next 不删除,将 temp \textit{temp} temp 向后移动一步。

需要注意的是,当 temp . next \textit{temp}.\textit{next} temp.next 需要删除时,删除结点之后,由于新的 temp . next \textit{temp}.\textit{next} temp.next 可能也要删除,因此不能将 temp \textit{temp} temp 向后移动。

遍历到链表末尾时,遍历结束。新链表的头结点为 dummyHead . next \textit{dummyHead}.\textit{next} dummyHead.next

代码

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        ListNode temp = dummyHead;
        while (temp.next != null) {
            if (temp.next.val == val) {
                temp.next = temp.next.next;
            } else {
                temp = temp.next;
            }
        }
        return dummyHead.next;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是链表的长度。需要遍历链表一次,对于每个要删除的结点,删除一个结点的时间是 O ( 1 ) O(1) O(1)

  • 空间复杂度: O ( 1 ) O(1) O(1)

举报

相关推荐

0 条评论