每日一恋 - LeetCode 203 & 19 & 237. Remove Linked List Elements(删除链表中的节点)

203. 删除链表中的节点

Remove all elements from a linked list of integers that have value val.

Example:

Input:  1->2->6->3->4->5->6, val = 6
Output: 1->2->3->4->5

删除链表中等于给定值 val 的所有节点。

示例:

输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5

解法一(Iteration):

首先处理链头就遇到待删除元素的情况,直到链头不是待删除元素,接着判断是否为空。若不为空,则判断下一个结点是否为空,不为空就检查其是否是待删除元素,若是则将当前结点的 next 指针指向当前结点 next 的 next 的结点,否则就继续遍历链表。

public ListNode removeElements(ListNode head, int val) {

    while (head != null && head.val == val) {
        head = head.next;
    }

    if (head == null)
        return null;

    ListNode prev = head;
    while (prev.next != null) {
        if (prev.next.val == val) {
            prev.next = prev.next.next;
        } else {
            prev = prev.next;
        }
    }
    return head;
}

解法二(Virtual Head Node):

解法一的优化,增加一个虚拟的头结点,不需要再对输入的头结点进行判断空和是否是删除元素的特殊处理。

public ListNode removeElements(ListNode head, int val) {
    ListNode dummyNode = new ListNode(-1);
    dummyNode.next = head;
    ListNode prev = dummyNode;
    while (prev.next != null) {
        if (prev.next.val == val) {
            prev.next = prev.next.next;
        } else {
            prev = prev.next;
        }
    }
    return dummyNode.next;
}

解法三(Recursion):

解法一的递归写法,注意在不删除当前结点的情况下,需要将当前结点指向递归完成后的头结点。

public ListNode removeElements(ListNode head, int val) {

    if (head == null)
        return null;

    ListNode res = removeElements(head.next, val);
    if (head.val == val)  // 将删除当前结点
        return res;
    else { // 不删除当前结点
        head.next = res;
        return head;
    }
}

或者

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

如果文章里有说得不对的地方请前辈多多指正~ 与君共勉~


19. 删除链表的倒数第N个节点

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明:

给定的 n 保证是有效的。

进阶:

你能尝试使用一趟扫描实现吗?

分析

题目要求一趟遍历删除倒数的第n个节点,我们不知道链表的长度,该如何知道第n个节点是哪个呢。其实可以使用快、慢两个指针来完成这一目标,快指针从链头开始先走n个节点,然后慢指针从链头出发,两者同时向前移动,当快指针到达末尾时,慢指针所在位置就是倒数第n个节点的前一个节点,这时候只要跳过它指向它的下一个节点即可。

public ListNode removeNthFromEnd(ListNode head, int n) {

    ListNode fast = head;
    // 快指针先走 n 步
    for (int i = 0 ; i < n ; i ++) {
        fast = fast.next;
    }

    ListNode slow = head;
    // 要删除第一个的情况
    if (fast == null) {
        return head.next;
    }

    // 当快指针走到结尾时,慢指针就是待删除结点的前一个结点
    while (fast.next != null) {
        fast = fast.next;
        slow = slow.next;
    }

    slow.next = slow.next.next;

    return head;
}

237. 删除链表中的节点

这道题与上一题乍一看都是删除链表中的一个节点,但不同的是这题给的不是整个链表,而是待删除的节点。我们知道要删除一个节点需要它的前驱节点的指针,但是这里是无法得到的,只能想一个变通的方法。所以仔细一想,只要交换给定节点和其下一个节点的内容,然后删除下一个节点,这样不就可以了。

public void deleteNode(ListNode node) {
    node.val = node.next.val;
    ListNode nextNode = node.next;
    node.next = nextNode.next;
    nextNode.next = null; // 别忘了置为null,垃圾回收
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值