每天一道Leetcode题19

294 阅读2分钟

题目

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

示例:

给定一个链表:1->2->3->4->5 n = 2
当删除了倒数第二个节点后,链表变为1->2->3->5

说明:

给定的n保证是有效的。

进阶:

你能尝试使用一趟扫描实现吗?


解题过程

直觉做法

遍历一遍链表,得到链表的长度len。再次遍历删除倒数第n个节点就是删除从列表开头的(len-n+1)的节点。即两次遍历方法。

看了官方题解才改正代码,没考虑到下面的情况
有两种极端情况是,列表只有一个节点,或者删除第一个节点。

因此官方题解是添加哑节点辅助,该节点位于列表头部。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 创建一个哑节点指向第一个节点
        ListNode * dummy = new ListNode(0);
        dummy->next = head;
        
        // 遍历得到链表长度length
        int length = 0;
        ListNode * first = head;
        while(first != NULL){
            length++;
            first = first->next;
        }
        
        //删除从列表头开始第(length-n+1)的节点
        length -= n;
        first = dummy;
        while(length > 0){
            length--;
            first = first->next;
        }    
        first->next = first->next->next;
        return dummy->next;
        
    }   
};

时间复杂度:O(L),第一次遍历L次得到列表长度L,第二次遍历L-n次,操作执行2L-n次。

空间复杂度:O(1)


优化

遍历了两遍链表才成功,是否可以一遍呢?

我们可以使用两个指针,让它们保持n个节点的距离,当第一个指针到达NULL时,第二个指针刚好到达倒数第n个节点。这里只遍历了一次,即一次遍历法。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 创建一个哑节点指向第一个节点
        ListNode * dummy = new ListNode(0);
        dummy->next = head;
        ListNode * slow = dummy;
        ListNode * fast = dummy;
        
        // 让两个指针保持n+1个节点的距离,因为我们要的是待删除节点的前一个节点的指针
        for(int i = 1; i <= n+1; i++){
            fast = fast->next;
        }
        
        while(fast != NULL){
            fast = fast->next;
            slow = slow->next;
        }
        
        slow->next = slow->next->next;
        return dummy->next;
        
    }   
};

时间复杂度:O(L),只需要遍历一次列表。

空间复杂度:O(1)。