Leetcode 單鏈表題型總結

Leetcode 單鏈表題型總結

自己刷題的一個小記錄,難度從easy --> hard,持續更新中。若有更好的方法,歡迎評論區討論呀。
876. 返回單鏈表的中間節點。如果有兩個中間節點,返回第二個。
兩種思路,
第一種是先遍歷一遍,記錄長度後,再遍歷到一半。時間複雜度O(n)
第二種是用兩個指針,一快一慢,快指針每次走兩步,慢指針每次走一步,當快指針走到鏈表最後時,慢指針所指的就是中間節點。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

'''
先遍歷一遍,記錄長度,再遍歷一半。
class Solution:
    def middleNode(self, head: ListNode) -> ListNode:
        if head.next ==None:
            return head
        length = 1
        phead = head
        while head.next !=None:
            length +=1
            head = head.next
        
        mid = length//2
        for i in range(mid):
            phead = phead.next
        return phead
'''
# 直接快慢指針,快的到頭以後,慢的就是中間值
class Solution:
    def middleNode(self, head: ListNode) -> ListNode:
        if head.next ==None:
            return head
        fast = head
        slow = head
        while fast and fast.next:
            fast = fast.next.next
            slow = slow.next
        return slow

206. 反轉單鏈表
兩種思路
遞歸
迭代

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
'''
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        # 遞歸版本,一直往後遍歷,每次建立一個反轉鏈接
        return self.reverse(head,None)
    
    def reverse(self, current, prev):
        if current == None:
            return prev
        
        nxt = current.next
        current.next = prev
        prev = current
        current = nxt
        
        return self.reverse(current, prev)
'''
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        # 迭代版本
        return self.reverse(head,None)
    
    def reverse(self, current, prev):
        if current == None:
            return prev
        while current!=None:
            nxt = current.next
            current.next = prev
            prev = current
            current = nxt
        return prev

237. 刪除單鏈表中的某一節點
這題要注意的是,並沒有給出完整的鏈表,函數參數中只是給了要刪除的節點。
但由於是單鏈表,沒法獲取被刪除節點前的節點,所以將被刪除節點的值改爲後面一個節點的值,然後刪除後面一個節點即可。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def deleteNode(self, node):
        """
        :type node: ListNode
        :rtype: void Do not return anything, modify node in-place instead.
        """
        # 沒有給完整的單鏈表,只是給了要刪除的節點!沒有head!
        node.val = node.next.val
        node.next = node.next.next

21. 合併兩個已排序的單鏈表
用兩個指針分別遍歷兩個鏈表。遇到較小的一個,就加到合併列表後面,並指針後移。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        newlist = ListNode(0)
        tmp = newlist
        while l1!=None and l2!=None:
            if l1.val<l2.val:
                tmp.next = l1
                l1 = l1.next
            else:
                tmp.next = l2
                l2 = l2.next
            tmp = tmp.next
        if l1!=None:
            while l1!=None:
                tmp.next = l1
                l1 = l1.next
                tmp = tmp.next
        if l2!=None:
            while l2!=None:
                tmp.next = l2
                l2 = l2.next
                tmp = tmp.next
        return newlist.next
            

83.給定一個排序後的單鏈表,刪除其中的重複節點,保證每個節點只出現一次。
思路:遇到重複的節點,就往後遍歷,直到節點不重複即可。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        tmp = head
        while tmp!=None:
            nxt = tmp.next
            while nxt!=None and nxt.val== tmp.val:
                nxt = nxt.next
            tmp.next = nxt
            tmp = nxt
        return head

141. 判斷單鏈表是否有環
思路:用快慢指針,如果有環,那麼兩個指針一定會相遇。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def hasCycle(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        # 快慢指針,如果有環,那麼總歸會相遇
        if head==None or head.next==None:
            return False
        fast = head.next
        slow = head
        flag = 0
        while fast!=slow:
            if fast==None or fast.next==None:
                return False
            fast = fast.next.next
            slow = slow.next
        return True

234.判斷一個單鏈表是否是迴文的。
思路1: 笨方法,遍歷鏈表,將鏈表的節點值存儲在數組中,再分別比較數組的頭尾。
思路2: 先遍歷一遍列表,記錄長度。然後將鏈表分成兩半,前面一半進行反轉,然後與後面一半比較是否完全相等。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    '''另外用一個數組將鏈表節點的值存下來,空間複雜度O(N)'''
    '''
    def isPalindrome(self, head):
        vals = []
        while head:
            vals += head.val,
            head = head.next
        return vals == vals[::-1]
    '''
    def isPalindrome(self, head: ListNode) -> bool:
        # 先遍歷一遍鏈表,記錄鏈表長度。
        # 然後從中間將鏈表切成前後兩半,並把前面一半進行反轉,然後與後面一半進行比較
        if head==None or head.next==None:
            return True
        node = head
        count = 0
        while node!=None:
            count+=1
            node=node.next
            
        node = head
        prev = None
        for i in range(count//2):
            nxt = node.next
            node.next = prev
            prev = node
            node = nxt
        if count%2==0:
            h2 = node
        else:
            h2 = node.next
        h1 = prev
        while h1 and h2:
            if h1.val!=h2.val:
                return False
            h1 = h1.next
            h2 = h2.next
        return True

203. 給定一個鏈表和一個值val,將鏈表中值爲val的節點都刪除。
注意考慮頭部節點需要刪除的情況即可。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeElements(self, head: ListNode, val: int) -> ListNode:
        
        if head==None:
            return head
        if head.next==None:
            if head.val == val:
                return None
            else:
                return head
        while head!=None and head.val==val:
            head=head.next
        node = head
        while node!=None:
            if node.next!=None and node.next.val ==val:
                node.next = node.next.next
            else:
                node = node.next
        
        return head

160. 找兩個鏈表的交點。
思路1: 先分別遍歷一遍兩個鏈表,記錄他們的長度l1和l2,讓長的那個鏈表先走|l1-l2|步,再同時走,就能走到交點處。
思路2: 更簡潔的一個方法,兩個鏈表同時從頭節點走,其中一個走到頭後,redirect到另一個鏈表的頭節點。這樣就能找到交點。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

'''
先分別記錄兩個鏈表的長度,然後讓長的那個先走“差值”步,再同時走,就能一起走到交點處

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        if headA == None or headB==None:
            return None
        node1 = headA
        node2 = headB
        length1, length2 = 0, 0
        while node1!=None:
            length1+=1
            node1 = node1.next
        while node2!=None:
            length2+=1
            node2 = node2.next
        if length1>length2:
            for i in range(length1-length2):
                headA = headA.next
        else:
            for i in range(length2-length1):
                headB = headB.next
        while headA!=headB:
            headA = headA.next
            headB = headB.next
        return headA
'''
'''
更簡潔的一個方法,兩個鏈表同時從頭節點走,其中一個走到頭後,redirect到另一個鏈表的頭節點。這樣就能找到交點'''
class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        if headA == None or headB==None:
            return None
        node1 = headA
        node2 = headB
        while node1!=node2:
            node1 = headB if node1==None else node1.next
            node2 = headA if node2==None else node2.next
        return node1

707. 實現一個單鏈表類,包括一系列添加節點、刪除節點的函數。

 class listNode:
    def __init__(self, val):
        self.val = val
        self.next = None
        
class MyLinkedList(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.head = None
        self.size = 0

    def get(self, index):
        """
        Get the value of the index-th node in the linked list. If the index is invalid, return -1.
        :type index: int
        :rtype: int
        """
        if index<0 or index>=self.size:
            return -1
        if self.head is None:
            return -1
        node = self.head
        for i in range(index):
            node = node.next
        return node.val

    def addAtHead(self, val):
        """
        Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
        :type val: int
        :rtype: None
        """
        newHead = listNode(val)
        newHead.next = self.head
        self.head = newHead
        self.size +=1
        
    def addAtTail(self, val):
        """
        Append a node of value val to the last element of the linked list.
        :type val: int
        :rtype: None
        """
        newnode = listNode(val)
        node = self.head
        if node ==None:
            self.head = newnode
        else:
            while node.next!=None:
                node = node.next
            node.next = newnode
        self.size+=1

    def addAtIndex(self, index, val):
        """
        Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
        :type index: int
        :type val: int
        :rtype: None
        """
        
        if index>0 and index <= self.size:
            node = self.head
            for i in range(index-1):
                node = node.next
            newnode = listNode(val)
            newnode.next = node.next
            node.next = newnode
            self.size +=1
        elif index<=0:
            self.addAtHead(val)
            

    def deleteAtIndex(self, index):
        """
        Delete the index-th node in the linked list, if the index is valid.
        :type index: int
        :rtype: None
        """
        if index>0 and index<self.size:
            node = self.head
            for i in range(index-1):
                node = node.next
            node.next = node.next.next
            self.size -=1
        elif index==0:
            self.head = self.head.next
            self.size -=1


# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)

1019.給定一個單鏈表,返回一個數組,數組中第i個元素是鏈表中第i個節點的next greater值,即最近的比第i個節點值大的節點值。
example:
Input: [1,7,5,1,9,2,5,1]
Output: [7,9,9,9,0,5,0,0]
思路:用一個棧來存儲‘還沒有遇到next greater的節點’,每次當前節點與棧頂進行比較。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

'''
用一個stack來存儲‘還沒有遇到next greater的節點’,每次當前節點與棧頂進行比較 '''
class Solution:
    def nextLargerNodes(self, head: ListNode) -> List[int]:
        if head==None:
            return None
        elif head.next == None:
            return [0]
        ans = []
        stack = []
        pos = -1
        while head:
            pos +=1
            ans.append(0)
            # 把棧頂元素和當前節點進行比較
            while stack and stack[-1][1]<head.val:
                # 小的話,就把棧頂元素彈出,並且寫到ans數組中
                # 直到棧爲空
                index, _ = stack.pop()
                ans[index] = head.val
            stack.append((pos,head.val))
            head = head.next
        return ans

817. 單鏈表的組成部分
給定一個單鏈表和一個數組,數組是單鏈表節點值的子集。返回一個number,代表數組中的值在單鏈表中分爲幾個相連部分。
example:
輸入:
head: 0->1->2->3
G = [0, 1, 3]
輸出: 2
Explanation: 0 and 1 are connected, so [0, 1] and [3] are the two connected components.
思路:遍歷單鏈表的節點,如果節點值在數組中出現,那麼往後遍歷,直到不出現則出現斷點,就表示number+=1。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    '''
    def numComponents(self, head: ListNode, G: List[int]) -> int:
        # 遍歷單鏈表,然後看連續的鏈表部分是否出現在list中
        node = head
        count = 0
        while node!=None:
            if node.val in G:
                while node!=None and node.val in G:
                    node = node.next
                count+=1
            if node!=None:
                node = node.next
        return count
    '''
    #更簡潔的寫法
    def numComponents(self, head, G):
        setG = set(G)
        res = 0
        while head:
            if head.val in setG and (head.next == None or head.next.val not in setG):
                res += 1
            head = head.next
        return res

445. 給定兩個單鏈表,分別表示兩個整數,返回兩個整數的和。且題目要求不能反轉鏈表。
example:
Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7
思路:由於不能反轉鏈表,那麼我想到的只能是把數存下來,相加後再構造新的鏈表。有更好的方法會再更新。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        # 不能反轉鏈表
        # 第一個方法,將鏈表遍歷後,得到數字,相加後再構造一個鏈表
        num1, num2 = 0,0
        while l1!=None:
            num1 = num1*10 + l1.val
            l1 = l1.next
        while l2!=None:
            num2 = num2*10 + l2.val
            l2 = l2.next
        x = num1+num2
        
        head = ListNode(0)
        if x == 0: return head
        while x:
            v, x = x%10, x//10
            head.next, head.next.next = ListNode(v), head.next
            
        return head.next

328. 給定一個單鏈表,把鏈表中的奇數節點都放到前面,偶數節點放到後面,且不改變奇數之間和偶數之間的相對順序。
思路:與86題相似,建立兩個空節點,然後奇數偶數分別連到後面,再合併鏈表。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def oddEvenList(self, head):
        dummy1 = odd = ListNode(0)
        dummy2 = even = ListNode(0)
        while head:
            odd.next = head
            even.next = head.next
            odd = odd.next
            even = even.next
            head = head.next.next if even else None
        odd.next = dummy2.next
        return dummy1.next

725. 給定一個單鏈表,和一個數字k,要求把鏈表分爲k個部分,且每個部分的元素個數相差不超過1。
example:
Input: root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
思路:首先考慮k比鏈表長度小的情況,直接分割即可。其他的,先遍歷鏈表,記錄長度len,len//k表示每個組元素的最少個數,len%k=num表示多的元素個數,分別在前num個塊中加上1個元素。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]:
        # 先記錄鏈表長度length,然後length/k,餘數yushu表示多的,那麼在前yushu個段加1個
        node = root
        length = 0
        while node!=None:
            length+=1
            node = node.next
        
        ans =[]
        node = root
        
        shang = length//k
        yushu = length%k
        
        for i in range(k):
            head = ListNode(0)
            s = head
            if i<yushu:
                for j in range(shang+1):
                    head.next = node
                    node = node.next
                    head = head.next
            else:
                for j in range(shang):
                    head.next = node
                    node = node.next
                    head = head.next
            head.next = None
            ans.append(s.next)
        return ans

24. 交換鏈表中每兩個相鄰的節點。
example:
Given 1->2->3->4, you should return the list as 2->1->4->3.

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def swapPairs(self, head):
        pre, pre.next = self, head
        while pre.next and pre.next.next:
            a = pre.next
            b = a.next
            pre.next, b.next, a.next = b, a, b.next
            pre = a
        return self.next

430. 把一個層級的,含有子節點的雙向鏈表進行flatten,表示成一個新的雙向鏈表。
example:
在這裏插入圖片描述
思路:用一個棧來存儲4、9節點。即遇到有子節點的節點,將後面的節點入棧。遍歷到最後一層的最後節點後,開始出棧,將節點加到後面,直到棧爲空。

"""
# Definition for a Node.
class Node:
    def __init__(self, val, prev, next, child):
        self.val = val
        self.prev = prev
        self.next = next
        self.child = child
"""
class Solution:
    # 每次遇到有child節點的節點,就把next入棧。遍歷到最後之後,再從棧裏pop出節點加在後面
    def flatten(self, head: 'Node') -> 'Node':
        stack = []
        node = head
        prev = node
        while node:
            if node.child!=None:
                if node.next:
                    stack.append(node.next)
                node.child.prev = node
                node.next = node.child
                node.child = None
            if not node.next and len(stack):
                curr = stack.pop()
                curr.prev = node
                node.next = curr
            node = node.next
        return head

1171. 給定一個單鏈表,刪除其中和爲0的部分。
example:
Input: head = [1,2,-3,3,1]
Output: [3,1]
Note: The answer [1,2,1] would also be accepted.
思路:用一個字典來存儲當前的累加值,如果累加值出現重複,那麼說明有和爲0的部分存在。把這部分節點刪去,同時注意刪去字典中存儲的這部分節點累加值。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeZeroSumSublists(self, head: ListNode) -> ListNode:
        # 用一個值來存當前的累加和
        # 再用一個字典來存累加和出現的次數
        node = head
        sums, zidian = 0, {}
        while node:
            sums += node.val
            if sums ==0:
                head = node.next
                zidian.clear()
            else:
                if sums not in zidian:
                    zidian[sums] = node
                else:
                    #zidian[sums].next = node.next
                    pre = zidian[sums]
                    sums2 = sums + pre.next.val
                    while sums2 != sums:
                        curr = zidian[sums2]
                        del zidian[sums2]
                        sums2 += curr.next.val
                    pre.next = node.next  
                #zidian[sums] = None
            node = node.next
        
        return head

86. 給定一個單鏈表和一個值x,把鏈表中小於x的節點放在前面,大於x的節點放到後面。
example:
Input: head = 1->4->3->2->5->2, x = 3
Output: 1->2->2->4->3->5
思路:和奇偶劃分類似,構造兩個新的節點。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def partition(self, head: ListNode, x: int) -> ListNode:
        l1 = ListNode(0)
        l2 = ListNode(0)
        s1,s2 = l1, l2
        while head:
            if head.val<x:
                l1.next = head
                l1 = l1.next
            else:
                l2.next = head
                l2 = l2.next
            head = head.next
        l2.next = None
        l1.next = s2.next
        return s1.next
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章