題目:刪除鍊錶的倒數第n個節點;
描述:給定乙個鍊錶,刪除鍊錶中倒數第n個節點,返回頭節點;
example:
輸入:1->2->3->4->5->null;2
輸出:1->2->3->5->null
輸入:1->null;1
輸出:null;
這題最先想到的解法是,先通過快慢節點,算出該鍊錶的長度lenth,然後再迴圈一次,到length-n(下標從0開始,所以是length-n)的位置,刪掉該節點();
public class solution
listnode fast = head.next;
listnode slow = head;
int step = 1;
int length = 0;
while(fast != null && fast.next!= null)
if(fast == null)else if(fast.next == null)
system.out.println("length="+length );
if(length == n)
//倒數第n個等於正數第length+1-n個;下標為length+1-n-1 = length -n;
listnode prenode = head;
listnode target = head.next;
int i =1;
while(prenode != null)
target = target.next;
prenode = prenode.next;
i++;
}return head;}}
這種做法有幾點不太好:
首先就是時間複雜度,假設鍊錶長度為m,快慢節點需要o(m/2),第二次迴圈,最差是o(m),最好是o(1).(太不穩定了啊是不是,話說如果刪除靠前的節點,實現較好時間複雜度的情況,那還用倒數幹嘛??)
算長度。而且長度分奇偶…可能算長度還有別的方法,但是當我寫下if-else if的時候…
下標計算。這裡很容易亂掉,前面說的被刪除的下標的length+1-n-1,但是實際上,我們要找的根本不是被刪的那個節點,而是被刪除節點的前繼節點,因為單向鍊錶刪除節點的方法:prenode.next = delnode.next=prenode.next.next;可以說跟被刪除節點沒有壓根沒有被用到。所以要麼只定義乙個prenode節點(長度就變成了length-n-1),要麼再定義雙指標(prenode,delnode);
變數太多了。這個應該只是我有的問題,就是從計算長度,到正式刪除節點,我定義了兩次雙指標,共計4個指標,再加上step,length,幾乎滿屏都是自定義變數(憨得讓人窒息)。
為了本憨憨的生命安全,所以我進化了,就有了.
需要搞定的幾個問題:
1.時間複雜度。這個題目的要求是最好時間複雜度為o(n);即要麼只有一次迴圈,要麼兩次以上迴圈加在一起確定等於length;
2.計算長度。如果不需要計算長度,那麼之前說的2.3問題都不是問題;
3.這是後來意識到的問題,假如刪除的就是頭節點應該怎麼辦,因為我已經不算長度了,那原先寫的length==n時相當於刪除頭節點,就不能用了。
先上**:
public listnode removenthfromend(listnode head, int n) {
listnode tempnode = new listnode(0);
tempnode.next= head;//head移動的時候,tempnode的值也會隨之變化嗎?
for(int i=0;i解釋一下:
時間複雜度,穩定的o(n)。首先被刪除節點的下標一定是length-n,一般想的肯定是從下標0到length-n,剛好刪除;但是說起來,length-n也只是一段距離而已,只要在做刪除的過程中,經過的是length-n距離,那整個迴圈從**開始都是一樣的。所以,寫法就成了,先讓某個節點跑個n距離,然後第二次迴圈,被刪除節點的前繼節點從頭開始,到先跑n個距離的節點值為null,剩餘這length-n,剛好。
定義的還是雙指標。如果只有乙個指標的話,肯定只要作為被刪除節點的前繼節點,那如果刪除的是頭節點,去哪找頭節點的前繼節點哦。而且鍊錶中,做雙節點還是挺常見的方法,比如找煉表中點之類的,本題解法一計算長度就是在利用雙指標先將到鍊錶中點的長度計算出來。
為什麼兩個指標都相當於指向了頭節點的前繼,而不是head;
第一:tempnode。也就是我在**塊中寫的第四個問題「為什麼返回的是tempnode.next而不是haed」。
乙個原因當然是head在整個過程中最後已經指向了null(見解釋第一條),另乙個原因就是,他解決了不計算長度,被刪除節點即頭節點的問題。tempnode是我們自定義的節點,迴圈又是從head開始,那後面怎麼動都跟tempnode沒關係。
並且,**塊中的第乙個問題:head移動,tempnode的值會變嗎,tempnode.next的值呢。首先tempnode當然不會,而head指標的移動,只是head所指向的位置發生變化,他沒有改變值,他一走了之後,tempnode.next指向的還是整個鍊錶的頭節點。而頭節點發生變化也只是在刪除操作(prenode.next = prenode.next.next;)之後才可能發生,總之跟head沒啥關係。
第二:prenode。prenode是作為被刪除節點的前繼節點而定義的,如果指向head,在第一次迴圈時,他就跟著head跑了(tempnode.next沒跑是因為tempnode沒動)。至於他為什麼定義在head之前,以及**塊中第三個問題「while迴圈判斷條件為什麼不加head.next != null」,見圖:
可見第二次迴圈之後,prenoded的下標正好是head==null,length-n-1,按照單向鍊錶刪除的方法,到這裡是對的。
到這裡基本就結束啦,第一次寫這麼長,可能有些疏漏,歡迎指正。
另外演算法這種東西呢,個人認為是沒有最好只有更好(所以大家還有更好的方法,歡迎一起交流啊),而且貴精不貴多(雖然我也還沒做過多少,也不知道怎麼好意思說這句話),一道題做完了,不丟開看下一題,而是想著怎麼效率更高,**量更少,才是學習演算法的正確姿勢啊(個人意見…而已)。
刪除鍊錶倒數第N個節點
1.問題 給定乙個鍊錶,刪除鍊錶的倒數第 n 個節點,並且返回鍊錶的頭結點。示例 給定乙個鍊錶 1 2 3 4 5,和 n 2.當刪除了倒數第二個節點後,鍊錶變為 1 2 3 5.2.演算法 暴力破解法 先計算得出鍊錶的長度m,然後將鍊錶長度和所給倒數字置相減,即loc m n 1,得出刪除節點的前...
刪除鍊錶倒數第n個節點
leetcode 題目 給定乙個鍊錶,刪除鍊錶的倒數第 n 個節點,並且返回鍊錶的頭結點。給定乙個鍊錶 1 2 3 4 5,和 n 2.當刪除了倒數第二個節點後,鍊錶變為 1 2 3 5.note n 鍊錶長度時,刪除頭節點 n 0時,不做任何操作。當第乙個指標first 比第二個指標領先n步,然後...
刪除鍊錶的倒數第N個節點
與查詢鍊錶的倒數第n個節點對比只改動了一行 查到倒數第n個節點後,將該節點的後續指標p1.next p1.next.next 即可 package 鍊錶中 public class nthnodefromendoflist return m 刪除倒數第n個節點 param args public s...