链表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道题之二的主要内容,如果未能解决你的问题,请参考以下文章