算法思想
一、暴力法:
没看答案
- 由于删除倒数第n个节点就等同于将链表反转后删除正数第n个节点,所以先将链表反转;
- 然后删除正数第n个节点;
- 再将删除操作后的链表顺序反转,即返回到最初链表的顺序。
# 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;
}
};