22 刪除鏈表的倒數第N個節點-20200405
題目
給定一個鏈表,刪除鏈表的倒數第 n 個節點,並且返回鏈表的頭結點。
示例
給定一個鏈表: 1->2->3->4->5, 和 n = 2.
當刪除了倒數第二個節點後,鏈表變爲 1->2->3->5.
說明
給定的 n 保證是有效的。
進階
你能嘗試使用一趟掃描實現嗎?
注意事項
- 鏈表並不是list和字典,這是一種自定義的數據結構,所以當沒有給出相應的方法時,需要自己寫遍歷。
- 這裏要刪除的是倒數的第N個元素,所以要注意,開始只給了head節點,沒有給出整個鏈表的長度。
思路一
先遍歷找出數組長度,然後再循環把倒數第n個元素跳過去。
修改經歷:
1. 超出時間限制。。。爲什麼呢?(第一次提交)
- 超出時間限制
2. 找出了問題,在第一個循環之前將temp=head,但是循環的時候操作時,temp=head.next。這樣的操作會一直迭代。(第二次提交)
- 解答錯誤
3. 由於對鏈表的不熟悉,導致在第二次循環的時候當i==length-n時,head=head.next.next。這裏要注意一點的是,python中的等號賦值相當於淺拷貝,所以臨時變量的操作對原鏈表的操作。還有,操作時是讓前一個的指針跳過當前節點指向下一個節點,而查詢的時候是讓節點逐個後移。(第三次提交)
- 解答錯誤
4. 沒有考慮到輸入爲[1,2]和2的情況,此時的輸出應該爲[2]。(第四次提交)
- 執行用時 :40 ms, 在所有 Python3 提交中擊敗了60.18%的用戶
- 內存消耗 :13.7 MB, 在所有 Python3 提交中擊敗了6.54%的用戶
心得體會:
在 temp=head時,一定要區分 temp=temp.next 和 temp.next = temp.next.next 的區別。
前者可以理解爲查詢,對原鏈表不操作。
後者改變了鏈表結構,所以head的結構也變化了。
還有理解temp和head代表的只是一個節點,next裏存的是下一個節點的地址。
最終代碼展示:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
length = 1
tempHead = head
while tempHead.next:
tempHead = tempHead.next
length += 1
if length-n == 0:
return head.next
else:
target = head
for i in range(0, length-1):
if i == (length-n-1):
target.next = target.next.next # 在操作時是把指針串起來
break
else:
target = target.next # 在指向的時候是用下一個節點代替當前節點
return head
思路二
官方給出的一次遍歷的思路,雙指針的方法。通過讓兩個指針中間間隔n個節點,使得當前一個指針到達末尾時,後一個指針正好落在要刪除的元素上。同時引入一個啞結點來防止出現特殊情況。
修改經歷:
1. 返回的時候寫的是head,但是在輸入爲[1]和1時,會報錯。預計是[],但是輸出爲[1]。(第一次提交)
- 解答錯誤
2. 將 return head 爲 return dummyNode.next。因爲兩指針都是dummyNode來的。(第二次提價)
- 執行用時 :44 ms, 在所有 Python3 提交中擊敗了42.32%的用戶
- 內存消耗 :13.8 MB, 在所有 Python3 提交中擊敗了6.54%的用戶
心得體會:
這種方法還是很好地,提前找到提前量。尤其是啞結點 dummyNode 設計的很妙,避免了第一次提交的錯誤。
最終代碼展示:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
dummyNode, counter = ListNode(-1), 0
dummyNode.next = head
fP, lP = dummyNode, dummyNode
while fP.next != None:
if counter < n:
fP = fP.next
else:
fP = fP.next
lP = lP.next
counter += 1
lP.next = lP.next.next
return dummyNode.next
思路三
遞歸迭代。設置一個全局變量,先通過遞歸找到鏈表的最後一個,然後遞歸輸出,輸出一次全局變量加一。當全局變量不爲n時,輸出當前節點;當全局變量爲n時,輸出爲下一個節點。相當於倒着鏈接鏈表,當遇到要刪除的元素時,就直接跳過去,讓上一個節點連接到下一個去。
大神就是大神!
這個就直接貼代碼了,反正我一時半會是寫不出來的。
最終代碼展示:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
global i
if head is None:
i=0
return None
head.next = self.removeNthFromEnd(head.next,n)
i+=1
return head.next if i==n else head