删除链表的倒数第N个节点-链表19-python&C++

算法思想

一、暴力法:

没看答案

  1. 由于删除倒数第n个节点就等同于将链表反转后删除正数第n个节点,所以先将链表反转;
  2. 然后删除正数第n个节点;
  3. 再将删除操作后的链表顺序反转,即返回到最初链表的顺序。
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head, n):
        head = self.ReverseLinkedList(head)
        head = self.RemoveNthFromBeginning(head, n)
        head = self.ReverseLinkedList(head)
        return head
    
    def ReverseLinkedList(self, head):
        pre = None
        while(head):
            temp = head.next
            head.next = pre
            pre = head
            head = temp
        return pre

    def RemoveNthFromBeginning(self, head, n):
        assert head != None
        head_new = head
        if n == 1:
            head = head.next
            head_new = head
        else:
            for i in range(n-1):
                if i == n - 2:
                    head.next = head.next.next
                else:
                    head = head.next
        return head_new

复杂度分析:

  • 时间复杂度:O(L),其中 L 是链表的长度。
  • 空间复杂度:O(1)。

二、快慢指针

  • 由于我们需要找到倒数第 n 个节点,因此我们可以使用两个指针 fast 和 slow 同时对链表进行遍历,并且 fast 比 slow 超前 n 个节点。当 fast 遍历到链表的末尾时,slow 就恰好处于倒数第 n 个节点。
  • 具体地,初始时 fast和 slow 均指向头节点。我们首先使用 fast 对链表进行遍历,遍历的次数为 n。此时,fast 和 slow 之间间隔了 n−1 个节点,即 fast 比 slow 超前了 n 个节点。
  • 在这之后,我们同时使用 fast 和 slow 对链表进行遍历。当 fast 遍历到链表的末尾(即 fast为空指针)时,slow 恰好指向倒数第 n 个节点。
  • 根据方法一和方法二,如果我们能够得到的是倒数第 n 个节点的前驱节点而不是倒数第 n 个节点的话,删除操作会更加方便。因此我们可以考虑在初始时将 slow 指向哑节点,其余的操作步骤不变。这样一来,当 fast 遍历到链表的末尾时,slow 的下一个节点就是我们需要删除的节点。
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head, n):
        pre = ListNode(100, head)
        slow = pre
        fast = head
        for i in range(n):
            fast = fast.next
        while(fast):
            fast = fast.next
            slow = slow.next
        slow.next = slow.next.next

        return pre.next

复杂度分析:

  • 时间复杂度:O(L),其中 L 是链表的长度。
  • 空间复杂度:O(1)。

C++

快慢指针

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    
    
public:
    int getLength(ListNode* head){
    
    
        int length = 0;
        while(head != nullptr){
    
    
            length++;
            head = head->next;
        }
        return length;
    }

    ListNode* removeNthFromEnd(ListNode* head, int n) {
    
    
        ListNode * pre = new ListNode(100);
        pre->next = head;
        ListNode * slow = pre;
        ListNode * fast = pre->next->next;
        int length = getLength(head);
        int count = length - n;
        while(count != 0){
    
    
            fast = fast->next;
            slow = slow->next;
            count--;
        }
        slow->next = fast;
        return pre->next;
    }
};

猜你喜欢

转载自blog.csdn.net/VaccyZhu/article/details/113809207