LeetCode 探索初級算法-鏈表:22 刪除鏈表的倒數第N個節點-20200405

LeetCode探索初級算法目錄


22 刪除鏈表的倒數第N個節點-20200405

題目

給定一個鏈表,刪除鏈表的倒數第 個節點,並且返回鏈表的頭結點。

示例

給定一個鏈表: 1->2->3->4->5, 和 n = 2.

當刪除了倒數第二個節點後,鏈表變爲 1->2->3->5.

說明

給定的 n 保證是有效的。

進階

你能嘗試使用一趟掃描實現嗎?


注意事項

  1. 鏈表並不是list和字典,這是一種自定義的數據結構,所以當沒有給出相應的方法時,需要自己寫遍歷。
  2. 這裏要刪除的是倒數的第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

上一篇:LeetCode 探索初級算法-鏈表:21 刪除鏈表中的節點-20200404

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章