• 【编程之路】面试必刷TOP101:链表(01-05,Python实现)


    面试必刷TOP101:链表(01-05,Python实现)

    1.反转链表(小试牛刀

    1.1 迭代法

    class Solution:
        def ReverseList(self , head: ListNode) -> ListNode:
            if head == None:
                return None
            p = head
            q = None
            while p:
                tmp = p.next
                p.next = q
                q = p
                p = tmp
            return q
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    时间复杂度: O ( n ) O(n) O(n),遍历链表一次
    空间复杂度: O ( 1 ) O(1) O(1),无额外空间使用

    1.2 递归法

    class Solution:
        def ReverseList(self , head: ListNode) -> ListNode:
            if head == None or head.next == None:
                return head
            res = self.ReverseList(head.next)
            head.next.next = head
            head.next = None
            return res
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    时间复杂度: O ( n ) O(n) O(n),相当于递归遍历链表
    空间复杂度: O ( n ) O(n) O(n),递归栈深度为链表长度 n n n

    2.链表内指定区间反转(小试牛刀

    2.1 头插迭代法

    class Solution:
        def reverseBetween(self , head: ListNode, m: int, n: int) -> ListNode:
            res = ListNode(-1) # 设置虚拟头结点
            res.next = head
            pre = res          # 前序结点
            cur = head         # 当前结点
            for i in range(1,m):
                pre = cur
                cur = cur.next
            for i in range(m,n):
                tmp = cur.next
                cur.next = tmp.next
                tmp.next = pre.next
                pre.next = tmp
            return res.next
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    时间复杂度:O(n),最坏情况下遍历全部链表
    空间复杂度:O(1),无额外空间使用

    2.2 递归法

    如果 m == 1,就相当于反转链表的前 n 个元素;
    如果 m != 1,我们把 head 的索引视为1,那么我们是想从第 m 个元素开始反转;如果把 head.next 的索引视为1,那么相对于 head.next 的反转区间应该是从第 m-1 个元素开始的。以此类推,就是一个递归问题。

    对于每次反转,如果 n == 1,相当于只颠倒第一个节点;如果 n != 1,则进入后续节点,也是一个递归问题。

    class Solution:
        def __init__(self):
            self.temp = None
        def reverse(self, head: ListNode, n: int) -> ListNode:
            if n == 1:
                self.temp = head.next
                return head
            node = self.reverse(head.next, n-1)
            head.next.next = head
            head.next = self.temp
            return node
        def reverseBetween(self , head: ListNode, m: int, n: int) -> ListNode:
            if m == 1:
                return self.reverse(head,n)
            node = self.reverseBetween(head.next, m-1, n-1)
            head.next = node
            return head
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    时间复杂度:O(n),最坏情况下遍历全部链表
    空间复杂度:O(n),递归栈深度最坏为 n

    3.链表中的节点每k个一组翻转(小试牛刀

    3.1 递归法

    class Solution:
        def reverseKGroup(self , head: ListNode, k: int) -> ListNode:
            tail = head
            for i in range(0,k):
                if tail == None:
                    return head
                tail = tail.next
            pre = None
            cur = head
            while cur != tail:
                temp = cur.next
                cur.next = pre
                pre = cur
                cur = temp
            print(head.val)
            head.next = self.reverseKGroup(tail, k)
            return pre
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    时间复杂度:O(n),一共遍历链表 n 个结点
    空间复杂度:O(n),递归栈最大深度为 n / k

    4.合并两个排序的链表(小试牛刀

    4.1 迭代法

    class Solution:
        def Merge(self , pHead1: ListNode, pHead2: ListNode) -> ListNode:
            if pHead1 == None:
                return pHead2
            if pHead2 == None:
                return pHead1
            head = ListNode(-1)
            cur = head
            while pHead1 != None and pHead2 != None:
                if pHead1.val <= pHead2.val:
                    cur.next = pHead1
                    pHead1 = pHead1.next
                else:
                    cur.next = pHead2
                    pHead2 = pHead2.next
                cur = cur.next
            if pHead1 == None:
                cur.next = pHead2
            if pHead2 == None:
                cur.next = pHead1
            return head.next
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    时间复杂度:O(n),最坏情况遍历 2 n 2n 2n 个结点。
    空间复杂度:O(1),无额外使用空间,新建的链表属于返回必要空间。

    4.2 递归法

    class Solution:
        def Merge(self , pHead1: ListNode, pHead2: ListNode) -> ListNode:
            if pHead1 == None:
                return pHead2
            if pHead2 == None:
                return pHead1
            if pHead1.val <= pHead2.val:
                pHead1.next = self.Merge(pHead1.next, pHead2)
                return pHead1
            else:
                pHead2.next = self.Merge(pHead1, pHead2.next)
                return pHead2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    时间复杂度:O(n),最坏相当于遍历两个链表每个结点一次
    空间复杂度:O(n),递归栈最大长度为 n

    5.合并k个已排序的链表(小试牛刀

    5.1 归并排序思想

    class Solution:
        def Merge(self , pHead1: ListNode, pHead2: ListNode) -> ListNode:
            if pHead1 == None:
                return pHead2
            if pHead2 == None:
                return pHead1
            head = ListNode(-1)
            cur = head
            while pHead1 != None and pHead2 != None:
                if pHead1.val <= pHead2.val:
                    cur.next = pHead1
                    pHead1 = pHead1.next
                else:
                    cur.next = pHead2
                    pHead2 = pHead2.next
                cur = cur.next
            if pHead1 == None:
                cur.next = pHead2
            if pHead2 == None:
                cur.next = pHead1
            return head.next
        
        def divideMerge(self, lists: List[ListNode], left: int, right: int) -> ListNode:
            if left > right:
                return None
            elif left == right:
                return lists[left]
            mid = (int)((left+right)/2)
            return self.Merge(self.divideMerge(lists, left, mid), self.divideMerge(lists, mid+1, right))
                
        def mergeKLists(self , lists: List[ListNode]) -> ListNode:
            return self.divideMerge(lists, 0, len(lists)-1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    时间复杂度:O(Nlogk),N 表示列表中所有链表的结点数量,K 表示链表的数量
    空间复杂度:O(logk),递归会使用到 O(logk) 空间代价的栈空间

    5.2 优先队列(巧妙)

    import heapq
    class Solution:
        def mergeKLists(self , lists: List[ListNode]) -> ListNode:
            dummy = ListNode(0)
            p = dummy
            head = []
            for i in range(len(lists)):
                if lists[i]:
                    heapq.heappush(head, (lists[i].val, i))
                    lists[i] = lists[i].next
            while head:
                val, idx = heapq.heappop(head)
                p.next = ListNode(val)
                p = p.next
                if lists[idx]:
                    heapq.heappush(head, (lists[idx].val, idx))
                    lists[idx] = lists[idx].next
            return dummy.next
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    时间复杂度:O(Nlogk),N 表示列表中所有链表的结点数量,k 表示链表的数量,优先队列中的元素不超过 k 个,那么插入和删除的时间代价为 O(logk),这里最多有 N 个点,对于每个点都被插入删除各一次,故总的时间代价即渐进时间复杂度为 O(Nlogk)。
    空间复杂度:O(k),优先队列中的元素不超过 k 个,故渐进空间复杂度为 O(k)。

    5.3 辅助数组

    class Solution:
        def mergeKLists(self , lists: List[ListNode]) -> ListNode:
            tmp = []
            for head in lists:
                while head:
                    tmp.append(head.val)
                    head = head.next
            if not tmp:
                return None
            tmp.sort()
            res = ListNode(-1)
            cur = res
            for i in range(len(tmp)):
                cur.next = ListNode(tmp[i])
                cur = cur.next
            return res.next
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    时间复杂度:O(NlogN),N 表示列表中所有链表的结点数量,首先遍历所有结点 O(N),排序 O(NlogN)。
    空间复杂度:O(N),辅助数组空间。

  • 相关阅读:
    ST-Link v2 下载 出现target dll has been cancelled 的错误的解决方法
    6.5 XSS 获取 Cookie 攻击
    【BMS软开系列】1、 ISO 26262功能安全标准 (一)
    Ubuntu 16.04 xrdp远程桌面
    系统瘫痪了如何解决?系统重装!
    【无标题】
    范畴论(Category Theory)的基本介绍
    小学生python游戏编程arcade----游戏界面按钮实现事件实现的三种方法
    精英反向黄金正弦鲸鱼算法-附代码
    Nuxt3第二篇【路由】
  • 原文地址:https://blog.csdn.net/be_racle/article/details/125363408