链表11:链表中删除元素的8道题之二

Posted 纵横千里,捭阖四方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表11:链表中删除元素的8道题之二相关的知识,希望对你有一定的参考价值。

我们继续看删除链表中元素的题目,第二组的这两个不算很难,而且其实就是一个题对不?

第二组:

【3】LeetCode 19. 删除链表的倒数第 N 个节点

【4】LeetCode 1474. 删除链表 M 个节点之后的 N 个节点。

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

我们还是看一下详细的要求:

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

示例:

输入:head = [1,2,3,4,5], n = 2输出:[1,2,3,5]

进阶要求:你能尝试使用一趟扫描实现吗?

如果不考虑使用一次扫描,我们可以先遍历一遍,找到链表总长度L,然后重新遍历,位置L-N+1的元素就是我们要删的。但是如果要一趟扫描该怎么做呢?

我们前面说过,还是先在脑子里快速过一下常用的数据结构和算法思想,看看哪些看上去能解决问题?

貌似栈可以,是不?先将元素全部压栈,然后弹出第N个的时候就是我们要的是不?OK,搞定一种方法。

我们还提到常见的思想中有个双指针,那我们定义first和second两个指针,first先走N步,然后second再开始走,当first走到队尾的时候,second就是我们要的节点对不?

OK,到此为止,我们的问题就解决了。

方法1:计算链表长度

首先从头节点开始对链表进行一次遍历,得到链表的长度 LL。随后我们再从头节点开始对链表进行一次遍历,当遍历到第 L-n+1L−n+1 个节点时,它就是我们需要删除的节点。

虽然这个方式不是最优的,但是确实能解决问题,在很多场景下也能用,所以我们先练一下,至少是个及格分

class Solution {    public ListNode removeNthFromEnd(ListNode head, int n) {        ListNode dummy = new ListNode(0, head);        int length = getLength(head);        ListNode cur = dummy;        for (int i = 1; i < length - n + 1; ++i) {            cur = cur.next;        }        cur.next = cur.next.next;        ListNode ans = dummy.next;        return ans;    }    public int getLength(ListNode head) {        int length = 0;        while (head != null) {            ++length;            head = head.next;        }        return length;    }}

方法二:使用栈来进行

在遍历链表的同时将所有节点依次入栈。然后我们弹出栈的第 nn个节点就是需要删除的节点,并且栈顶的节点就是待删除节点的前驱节点,这样删除操作也十分方便。看代码:

class Solution {    public ListNode removeNthFromEnd(ListNode head, int n) {        ListNode dummy = new ListNode(0, head);        Deque<ListNode> stack = new LinkedList<ListNode>();        ListNode cur = dummy;        while (cur != null) {            stack.push(cur);            cur = cur.next;        }        for (int i = 0; i < n; ++i) {            stack.pop();        }        ListNode prev = stack.peek();        prev.next = prev.next.next;        ListNode ans = dummy.next;        return ans;    }}

方法三 双指针

那我们定义first和second两个指针,first先走N步,然后second再开始走,当first走到队尾的时候,second就是我们要的节点对不?

class Solution {    public ListNode removeNthFromEnd(ListNode head, int n) {        ListNode dummy = new ListNode(0, head);        ListNode first = head;        ListNode second = dummy;        for (int i = 0; i < n; ++i) {            first = first.next;        }        while (first != null) {            first = first.next;            second = second.next;        }        second.next = second.next.next;        ListNode ans = dummy.next;        return ans;    }}

二.leetcode 1474: 删除链表 M 个节点之后的 N 个节点

前面的问题解决之后,你发现先1474题毫无压力,先看题意:

给定链表 head 和两个整数 m 和 n. 遍历该链表并按照如下方式删除节点:

开始时以头节点作为当前节点.

保留以当前节点开始的前 m 个节点.

删除接下来的 n 个节点.

重复步骤 2 和 3, 直到到达链表结尾.

在删除了指定结点之后, 返回修改过后的链表的头节点.

示例1:

输入: head = [1,2,3,4,5,6,7,8,9,10,11,12,13], m = 2, n = 3输出: [1,2,6,7,11,12]解析: 保留前(m = 2)个结点,  也就是以黑色节点表示的从链表头结点开始的结点(1 ->2).删除接下来的(n = 3)个结点(3 -> 4 -> 5), 在图中以红色结点表示.继续相同的操作, 直到链表的末尾.返回删除结点之后的链表的头结点.

 这个题目其实就是在前面的问题上加了点遍历和计数:

class Solution {     ListNode deleteNodes(ListNode head, int m, int n) {        int count = m;        ListNode cur = head, tail = NULL;        while(cur)        {          count = m;          while(cur && count--)          {            tail = cur;            cur = cur.next;          }          count = n;          while(cur && count--)          {            cur = cur.next;          }          tail.next = cur;        }        tail.next = NULL;        return head;    }};

以上是关于链表11:链表中删除元素的8道题之二的主要内容,如果未能解决你的问题,请参考以下文章

链表10:链表中删除元素的8道题之一

每日一题之LeetCode237删除链表中的节点876链表的中间节点

20165332第十周课下作业

被火车撞了都不能忘记的几道题(你会了吗?)

删除排序链表中的重复元素(简单)

删除有序链表中相同的元素ii