To Dark Mode
Featured Images
Photo by JJ Ying on Unsplash

Linked List

Zhenghao Wu

Wednesday, February 9, 2022 2 min read

Status: In Progress

Post Details

This post is part 1 of 11 in the algorithm series.

View all articles in this series
  1. Array
  2. Binary
  3. Dynamic Programming
  4. Graph
  5. Heap
  6. Interval
  7. Linked List (current)
  8. Matrix
  9. Misc
  10. String
  11. Tree
Table of Contents

2. 两数相加

https://leetcode-cn.com/problems/add-two-numbers

给两个非空链表,每个节点储存一位数字,按逆序排序。返回一个相同形式的链表,表示两个链表的和。

数据在链表中是倒序的,这非常的便于处理计算时出现的进位。那最简单的方式就是从两个链表的入口开始计算,直到两个链表走到末尾。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        def getValue(node):
            return node.val if node != None else 0
        sep = 0
        amount = getValue(l1) + getValue(l2) + sep
        sep = int(amount / 10)
        returnList = ListNode(val=amount % 10)
        currentListPt = returnList
        while l1 != None or l2 != None:
            try:
                l1 = l1.next if l1.next else None
            except AttributeError:
                pass
            try:
                l2 = l2.next if l2.next else None
            except AttributeError:
                pass
            if l1 == None and l2 == None:
                break
            amount = getValue(l1) + getValue(l2) + sep
            sep = int(amount / 10)
            currentListPt.next = ListNode(val=amount % 10)
            currentListPt = currentListPt.next
        if sep != 0:
            currentListPt.next = ListNode(val=sep)
        return returnList

这种方式,LeetCode 的官方题解 称为模拟,时间复杂度受两链表长度的影响 $\mathcal{O}(\max(m,n))$ (m, n 分别为两链表的长度)。

第二种方法:递归

未完待续。

19. 删除链表的倒数第 N 个结点

https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list

因为需要删除倒数第 n 个结点,则需要得到指向该结点前一位置的指针,然后将指针的 next 指向 next.next 位置则实现倒数第 n 个结点的删除。

而找到第 n 个结点前后指针的方法可以使用快慢指针:后指针先走 n 步,然后前指针再移动,等后指针到达链表末尾时,前指针则到达 n 结点前一位置。其中需要注意边界条件,如果后指针先移动后,已经达到链表末尾,则链表长度为1,直接返回空链表(head.next)。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        p1 = p2 = head
        for _ in range(n):
            p1 = p1.next
        if not p1:
            return head.next
        while p1.next != None:
            p1 = p1.next
            p2 = p2.next
        p2.next = p2.next.next
        return head

因为只进行一次扫描,则时间复杂度为 $O(n)$

21. 合并两个有序链表

https://leetcode-cn.com/problems/merge-two-sorted-lists

主要的思路是使用两个指针指向两个升序链表中,还未加入新链表的元素。每步比较两个指向元素的大小,将较小的那个一加入新链表中。其中需要对边界条件进行处理,当一个指针指向空元素时,则直接将另一个指针指向的元素加入新链表中。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
        if not list1 and not list2:
            return list1
        if not list2:
            return list1
        elif not list1:
            return list2
        
        new_list_head = ListNode()
        new_list_p = new_list_head
        l1p = list1
        l2p = list2

        while l1p or l2p:
            try:
                if l1p.val <= l2p.val:
                    new_list_p.next = l1p
                    l1p = l1p.next
                    new_list_p = new_list_p.next
                else:
                    new_list_p.next = l2p
                    l2p = l2p.next
                    new_list_p = new_list_p.next
            except AttributeError:
                if l1p:
                    new_list_p.next = l1p
                    l1p = l1p.next
                    new_list_p = new_list_p.next
                elif l2p:
                    new_list_p.next = l2p
                    l2p = l2p.next
                    new_list_p = new_list_p.next
        return new_list_head.next

需要注意的是,新链表的构建,初始化了一个数值为 0 的链表节点。这个节点在最后结果中并不需要,所以在最后返回时,返回该链表头元素的下一元素 new_list_head.next

时间上,只进行一次扫描,所以时间复杂度为 $O(m+n)$, $m$ 为链表1的长度, $n$ 为链表2的长度。

Article Card

For "Linked List"

Author Zhenghao Wu
Publish & Update Date 2022-02-09
Tags Placeholder
Extra Materials

Related Posts