關於鏈表的一些操作總結

鏈表反轉

這是一個簡單的鏈表操作問題,在leetcode上面有52.7%的通過率,難度是簡單。但是還是想在這裏基於python做一下總結,順便總結一下鏈表的各種操作。

首先先看一下leetcode上面的題目:

反轉一個單鏈表。

示例:

輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
進階:
你可以迭代或遞歸地反轉鏈表。你能否用兩種方法解決這道題?

看完了題目,很直白,就是轉過來。我們嘗試對這道題進行解決。這道題用python至少會有三種解決方案。
首先是鏈表的數據結構定義:

# Definition for singly-linked list.
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
  1. 將鏈表遍歷進list中,然後利用切片反轉list,再將list填充到鏈表中即可。這是最簡單的一種思考邏輯,但是也比較消耗性能。時間和空間複雜度都爲O(n)。
def loop(head):
    temp = []
    while head is not None:
        temp.append(head)
        head = head.next
    temp = temp[::-1]
    for i, n in enumerate(temp):
        if i + 1 < len(temp):
            n.next = temp[i + 1]
        else:
            n.next = None
    return temp[0] if temp else None
  1. 另一種迭代算法,是一種純粹交換的迭代,筆者這裏截取了leetcode速度最快的一種。
def reverseList(head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if not head:
        return None
    it = head; jt = head.next
    it.next = None
    while jt:
        tmp = it
        it = jt
        jt = jt.next
        it.next = tmp
    return it

這一波交換操作,我們可以畫個示意圖就知道他的交換是一種怎麼樣的交換。

在這裏插入圖片描述

從圖中可以看出,循環的作用就是將反向指針進行保存。同時令將指針轉向的功能。

  1. 最後一種方案是採用遞歸的方式進行鏈表反轉。這種方式也需要一定的理解。我們先展示一下代碼。
def reverseList(head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if head is None or head.next is None:
        return head
    end = reverseList(head.next)
    head.next.next = head
    head.next = None
    return end

這種解法其實理解起來只有兩部分內容,傳遞反向指針和進行指針反向拼接。我們先來理解一下指針反向拼接這個操作。

1 -> 2 -> 3 -> 4 -> None
依次:
3(head) -> 4(head.next) -> 3(head.next.next)
3 -> None

如此循環即可將鏈表反轉過來。但是還有個關鍵就是將最後一個指針傳遞出來。我們可以看到之前的代碼中,end傳出來後是一直沒有做任何操作的。不停的return出最後一個指針。所以就將最後一個指針傳遞了出來。

以上就是鏈表反轉的3中方法。除此之外還想寫一些鏈表的簡單操作。

快慢指針

何爲快慢指針,即對鏈表進行兩個不同步頻的指針標記遍歷。最經典的是慢指針走一步,快指針走兩步。
快慢指針有很多的應用,比如說:

  1. 判斷一個鏈表是否存在環
def hasCycle(head):
    """
    :type head: ListNode
    :rtype: bool
    """
    if head is None or head.next is None:
        return False
    fast, slow = head.next.next, head.next
    while fast is not slow:
        if fast is None or fast.next is None:
            return False
        fast = fast.next.next
        slow = slow.next
    return True

兩個指針並排走,如果有環的話快指針最終會指向慢指針的位置。沒有環的話,快指針會指向None後退出。

當然這道題的解法不止這一樣,還可以利用set進行判斷。

  1. 輸出鏈表中的倒數第K個節點

這道題利用快慢指針的思路是這樣的。定義兩個指針,第一個指針向前走k-1步;第2個指針保持不動;到第k步時第2個指針也開始移動。由於兩個指針始終保持着k-1的距離,所以當快指針到達末尾時,慢指針剛好指向倒數第k個。

def count_back(head, k):
    if head is None:
        return head
    fast, slow = head, head
    for i in range(k - 1):
        fast = fast.next
        if fast is None:
            return None
    while fast is not None:
        fast = fast.next
        slow = slow.next
    return slow

這是關於鏈表的兩種比較簡單的操作,反轉和快慢指針。挺常見的面試題,在這裏做一些記錄分享。

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