LeetCode刷題Medium篇 Remove Nth Node From End of List
題目
Given a linked list, remove the n-th node from the end of list and return its head.
Example:
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.
Note:
Given n will always be valid.
Follow up:
Could you do this in one pass?
十分鐘嘗試
1. 第一個反應,不從尾部,從頭部開始,因為尾部沒有指標。size減去n就可以,但是size計算需要遍歷一遍才知道。不是one pass 演算法
2.如何實現one pass沒有想到
先按照第一種思路寫程式碼試試吧,寫程式碼過程中出現一個遺漏點:如果刪除的是第一個元素的情況沒有處理,這個時候head=head.next。我處理的是非第一個節點的情況。程式碼如下,通過測試,感覺不夠簡潔:
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { int length=0; ListNode curr=head; while(curr!=null){ length++; curr=curr.next; } int postion=length-n+1; curr=head; int count=1; int pre=postion-1; if(pre==0){ head=head.next; return head; } while(curr!=null){ if(count==pre){ curr.next=curr.next.next; } curr=curr.next; count++; } return head; } }
看了答案後,發現了思路簡潔的方法,為了去掉一些corner case,比如我忽略的情況,去掉的是第一個元素等等。可以增加一個dummy node,這樣可以簡化程式碼邏輯。因為如果刪除第一個元素,head指標需要移動,增加dummy節點後,統一返回的dummy.next。學習了思路之後修改一版如下:
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy=new ListNode(0); //dummy.next=head,不是dummy=head dummy.next=head; ListNode curr=head; int length=0; while(curr!=null){ length++; curr=curr.next; } length-=n; curr=dummy; while(length-->0){ curr=curr.next; } curr.next=curr.next.next; //head可能移動,比如只有兩個元素,刪除第一個,head=head.next,所以返回是dummy.next return dummy.next; } }
One pass解法
1. 建立dummy node,設定兩個指標first和second,初始都指向dummy
2. 移動n個節點,first比second間隔n個節點。
3 迴圈移動first和second,直到first為空,此時second的位置就是第k個元素的前一個
4 修改指標刪除節點
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
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;
}
}
進一步思考
以前做過刪除單鏈表中的某個元素,當時也是碰上corner case,比如刪除head節點的情況,當時沒有利用dummy node處理。是否也可以這樣處理呢?
https://leetcode.com/problems/remove-linked-list-elements/
這是當時的題目。解法裡面的確單獨處理了,當pre==null的時候 head=head.next;
Remove all elements from a linked list of integers that have value val.
Example:
Input: 1->2->6->3->4->5->6, val = 6 Output: 1->2->3->4->5
來,為了整合思路,試試今天的dummy方法。完美通過,記住關鍵點:在尋找元素的時候,不想等才移動curr,如果相同,不需要移動curr。有人沒有用dummy node,當然可以,無非需要處理head=head.next的情況,我這裡以後統一用dummy node。程式碼如下:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head==null) return null;
ListNode dummy=new ListNode(0);
dummy.next=head;
ListNode curr=dummy;
while(curr!=null&&curr.next!=null){
if(curr.next.val==val){
curr.next=curr.next.next;
}
else{
//不相等才移動curr,相等不用
curr=curr.next;
}
}
return dummy.next;
}
}