1. 程式人生 > >Leetcode(19)刪除連結串列的倒數第N個節點

Leetcode(19)刪除連結串列的倒數第N個節點

題目描述
給定一個連結串列,刪除連結串列的倒數第 n 個節點,並且返回連結串列的頭結點。
示例:
給定一個連結串列: 1->2->3->4->5, 和 n = 2.
當刪除了倒數第二個節點後,連結串列變為 1->2->3->5.
說明:
給定的 n 保證是有效的。
進階:
你能嘗試使用一趟掃描實現嗎?

解題思路
方法一、遍歷兩次連結串列
刪除倒數n的節點,首先需要知道整個連結串列的長度N,就可以轉化為刪除連結串列第N-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;
        int length=0;
        ListNode *first=head;
        while(first!=NULL)
        {
            length++;
            first=first->next;
        }        
        length-=n;
        first=dummy;
        while(length>0)
        {
            length--;
            first=first->next;
        }
        first->next=first->next->next;            
        return dummy->next;
    }
};

方法二、一次便利連結串列
上述演算法可以優化為只使用一次遍歷。我們可以使用兩個指標而不是一個指標。第一個指標從列表的開頭向前移動 n+1 步,而第二個指標將從列表的開頭出發。現在,這兩個指標被 n 個結點分開。我們通過同時移動兩個指標向前來保持這個恆定的間隔,直到第一個指標到達最後一個結點。此時第二個指標將指向從最後一個結點數起的第 n 個結點。我們重新連結第二個指標所引用的結點的 next 指標指向該結點的下下個結點。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *dummy=new ListNode(0);
        dummy->next=head;
        ListNode *first=dummy;
        ListNode *second=dummy;
        for(int i=1;i<=n+1;i++)
        {
            first=first->next;
        }
        while(first!=NULL)
        {
            first=first->next;
            second=second->next;
        }
        second->next=second->next->next;
        return dummy->next;
    }
};