0
点赞
收藏
分享

微信扫一扫

《LeetCode刷题计划》——移除链表元素(三种方法来实现)

慕犹清 2022-05-02 阅读 22

目录

 质朴做法(要考虑特殊情况)

定义虚拟头节点来简化逻辑的做法 

递归做法


废话不多说,上菜 😎

 

 质朴做法(要考虑特殊情况)

💡分析:

// 朴素做法
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if (head == null) return head;  // 如果链表为空直接返回
        // 处理当需要删除头结点的时候,因为正常的删除都是需要先找到要删除结点的上一个结点,所有对这种情况要进行特判
        while (head.val == val && head != null) { // 因为删除头结点后,新的头结点可能还需要删除
            head = head.next;
            if (head == null) return head; // 处理特殊情况,当链表的的最后一个元素需要被删除时
            // 直接return就好,此时head为空,如果再进行head.val == key的判断就会发生空指针异常
        }

        // 创建一个引用cur去完成链表的遍历(头节点是整个链表的灵魂,不能直接使用,避免丢失链表)
        // 此时的头结点绝对不是要删除的元素,所有我们可以用正常的方法进行删除
        ListNode cur = head;
        while (cur != null && cur.next != null) { // 删除一个结点,首先要找到他的上一个结点
            if (cur.next.val == val) {
                cur.next = cur.next.next;
            }
            else {
                cur = cur.next; // 继续向后走,看接下来还有没有要删除的结点
            }
        }
        return head;
    }
}


定义虚拟头节点来简化逻辑的做法 

💡分析:

// 设置一个虚拟头结点来进行操作
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        // 设置一个虚拟头结点,可以简化逻辑,这样就不用为删除头结点单独考虑了
        ListNode dummyHead = new ListNode(0, head); // 调用带两个参数的构造方法,对新建的结点进行初始化,并将该结点指向链表的头结点
        // 创建一个引用cur去完成链表的遍历(此时的虚拟头节点是整个链表的灵魂,不能直接使用,避免丢失链表)
        // 不用单独考虑链表为空的情况,应为当链表为空即cur.next == null,循环进不去,直接就返回了
        ListNode cur = dummyHead;
        while (cur.next != null) {
            if (cur.next.val == val) {
                cur.next = cur.next.next;
            }
            else {
                cur = cur.next;
            }
        }
        return dummyHead.next; // 返回真正的头结点
    }
}

递归做法

💡首先,链表可以想象成一个头结点加上它后面一个更短的结点。如图所示:

如果头节点对应的数值不等于 val ,原问题的结果就是头节点后面挂接上子问题求得的紫色的链表,否则,结果就是子问题求得的紫色的链表

🌰看完后你可能不太理解,那么我们来画图来实践一下: 

 递归的确不好理解,在短短几行代码中,他看似什么都没干(其实什么都干了)

强烈建议大家自动动手画一下递归中递和归的过程,只有你亲身画了,你才知道递归的妙处。

举报

相关推荐

0 条评论