鏈表“倒數”問題兩個解決思路

leetcode有道題就是問的這個問題: leetcode:Remove Nth Node From End of List[E]

鏈表的問題

這是鏈表中非常常見的問題,衆所周知,鏈表慢就慢在遍歷查找,而對於單鏈表來說,每次必須從頭開始搜索,這樣使得鏈表在處理“倒數”這個概念的時候,特別無力。常規的做法必須要2遍遍歷:1遍計算鏈表長度len,1遍搜索倒數的元素len-n。(當然,你可以通過加入鏈表長度變量或者使用雙向鏈表解決這個問題。)

但是題目要求是一遍完成,有沒有一遍的思路呢?其實是有的,那就是雙指針或遞歸。

解決思路一 ——雙指針

這裏有個常用的做法去解決“倒數問題”:雙指針。

雙指針常用做法是:
- 一個指針用來作爲參考,控制長度(作爲循環停止條件)
- 一個指針延遲啓動用來跑“倒數”。

第一個指針先運行n個數,然後打開第二個指針,這樣,當第一個指針跑完時,第二個指針剛好跑過Len-N數,這樣就找到了倒數第n個數。

注意:由於刪除操作比較特殊,必須找到前一個節點才能刪除下個節點,所以一般刪除操作我們會構造一個虛擬節點作爲開頭,以防開頭節點被刪除。

public class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode newhead = new ListNode(-1);  //防止頭被刪除
        newhead.next = head;
        ListNode point1 = newhead;
        ListNode point2 = newhead;
        for(;point1 != null;point1 = point1.next,n--)  //point1 控制長度
        {
            if(n < 0)
                point2 = point2.next;   //point2延遲啓動
        } 
        point2.next = point2.next.next;
        return newhead.next;
    }
}

解決思路二 —— 遞歸

除了用雙指針外,還可以考慮用遞歸,凡是這種涉及單鏈表插入刪除操作的時候,都可以考慮用遞歸,因爲插入和刪除都需要涉及它的父親操作。我們考慮最後一個元素是第一層,然後逐級返回,當返回到第N+1層(也就是父親節點所在層數)就開始刪除操作。

public class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode newhead = new ListNode(-1);
        newhead.next = head;
        remove(newhead,n); 
        return newhead.next;
    }

    private int remove(ListNode node, int n) {
        if(node.next == null) return 1;
        int level = remove(node.next,n)+1; //層數+1
        if(level == n+1)    //找到了父親
            node.next = node.next.next;
        return level;   
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章