【数据结构与算法】之深入解析“删除链表的倒数第N个结点”的求解思路与算法示例

举报
Serendipity·y 发表于 2022/02/17 01:24:46 2022/02/17
【摘要】 一、题目要求 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。示例 1: 输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5] 12 示例 2: ...

一、题目要求

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

在这里插入图片描述

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

  
 
  • 1
  • 2
  • 示例 2:
输入:head = [1], n = 1
输出:[]

  
 
  • 1
  • 2
  • 示例 3:
输入:head = [1,2], n = 1
输出:[1]

  
 
  • 1
  • 2
  • 提示:
    • 链表中结点的数目为 sz;
    • 1 <= sz <= 30;
    • 0 <= Node.val <= 100;
    • 1 <= n <= sz。

二、求解算法

① 双指针

  • 题目要求删除倒数的第 n 个节点,可以先让快指针先走 n 步,接着快慢指针一起向前走,知道快指针指向尾部,这样慢指针之后的就是要删除的:

在这里插入图片描述

  • 定义虚拟的头节点,这样都链表中所有的节点都是一样的操作;
  • 定义两个指针分别是 fast 和 slow;
  • 先让 fast 指针走 n+1 步,这样做的目的是以后 fast 指针指向链表尾部为空的时候,slow 指针正好指向要删除的节点前面的节点;
  • 让快慢指针一起运动,直到快指针指向空;
  • 删除慢指针后面的元素,返回虚拟头节点的下一个元素即可。
  • Swift 示例:
func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
    guard head?.next != nil else {
        if head == nil || n == 1 {
            return nil
        } else {
            return head
        }
    }
    
    var count = 1
    var current = head
    var toDeletePre: ListNode?
    while current?.next != nil {
        current = current?.next
        count += 1
        if count == n + 1 {
            toDeletePre = head
        } else if count > n + 1 {
            toDeletePre = toDeletePre?.next
        }
    }
    
    if count == n {
        return head?.next
    }
    
    if toDeletePre != nil {
        toDeletePre?.next = toDeletePre?.next?.next
    }
    return head
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • Java 示例:
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummyhead = new ListNode(-1,head);

        ListNode fast = dummyhead;
        ListNode slow = dummyhead;

        for(int i = 0; i <= n; ++i){
            if(fast != null)
                fast = fast.next;
        }
        while (fast != null){
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return dummyhead.next;
    }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

② 计算链表长度(LeetCode官方解法)

  • 一种容易想到的方法是,首先从头节点开始对链表进行一次遍历,得到链表的长度 L。随后我们再从头节点开始对链表进行一次遍历,当遍历到第 L−n+1 个节点时,它就是我们需要删除的节点。
  • 为了与题目中的 n 保持一致,节点的编号从 1 开始,头节点为编号 1 的节点。
  • 为了方便删除操作,可以从哑节点开始遍历 L−n+1 个节点。当遍历到第 L−n+1 个节点时,它的下一个节点就是需要删除的节点,这样只需要修改一次指针,就能完成删除操作。

在这里插入图片描述

  • C++ 示例:
class Solution {
public:
    int getLength(ListNode* head) {
        int length = 0;
        while (head) {
            ++length;
            head = head->next;
        }
        return length;
    }

    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;
        delete dummy;
        return ans;
    }
};

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • Java 示例:
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;
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

文章来源: blog.csdn.net,作者:Serendipity·y,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/Forever_wj/article/details/122548202

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。