5.8 力扣 堆 合并K个链表 迭代后序遍历

942.增减字符串匹配
在这里插入图片描述
我们维护当前未使用的最小和最大的数,它们对应的区间为当前未使用的数的集合。从左向右扫描字符串,如果碰到 ‘I’,就取出当前最小的数,否则取出当前最大的数。
在这里插入图片描述

class Solution:
    def diStringMatch(self, S: str) -> List[int]:
        n=len(S)
        l,h=0,n
        ans=[]
        for i in S:
            if i=='I':
                ans.append(l)
                l+=1
            if i=='D':
                ans.append(h)
                h-=1
        return ans+[l]

堆: heapq模块
栈顶元素heap[0]总是最小的那个元素,此外,接下来的最小元素可以一次通过heapq.heappop()的方法轻松的找到
nlargest()和nsmallest():在某个集合中找出最大或最小的N个元素

nums=[1,2,3,4,5,6]
heapq.nlargest(3,nums)

堆是二叉树,最大堆中父节点大于或等于两个子节点,最小堆父节点小于或等于两个子节点。堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入
堆的主要操作是插入和删除最小元素(元素值本身为优先级键值,小元素享有高优先级)
heapq有两种方式创建堆, 一种是使用一个空列表,然后使用heapq.heappush(堆,值)函数把值加入堆中,同时维持堆得排序要求。
另外一种就是使用heap.heapify(list)转换列表成为堆结构
如果需要删除堆中最小元素并加入一个元素,可以使用heapq.heaprepalce() 函数:heapq.heapreplace(nums, 23)

heapreplace(a,x) 弹出最初在a中的最小值,而不管x的值如何,然后将x压进去
heappushpop(a,x) 在弹出最小值之前将x推送到a上.

703 数据流中第K大元素
在这里插入图片描述
堆排序:

import heapq
class KthLargest:
    def __init__(self, k: int, nums: List[int]):
        self.k=k
        self.pool=heapq.nlargest(self.k,nums)
        heapq.heapify(self.pool)
    def add(self, val: int) -> int:
        if len(self.pool)<self.k:
            heapq.heappush(self.pool,val)
        else:
            heapq.heappushpop(self.pool,val)
        return self.pool[0]

面试题17。14 最小K个数
在这里插入图片描述
堆排序:
在这里插入图片描述
堆 复杂度Nlogk

import heapq
class Solution:
    def smallestK(self, arr: List[int], k: int) -> List[int]:
        pool=heapq.nsmallest(k,arr)
        heapq.heapify(pool)
        return [heapq.heappop(pool) for x in range(len(pool)) ]
        #return sorted(arr)[:k] 一行更快

快速排序: 最慢
#快速选择算法 复杂度N

        #快排
        def kuaipai(arr):
            n=len(arr)
            if n<2:
                return arr
            mid=n//2
            pivort=arr[mid]
            left,right=[],[]
            arr.remove(pivort)
            for i in range(len(arr)):
                if arr[i]<pivort:
                    left.append(arr[i])
                else:
                    right.append(arr[i])
            return kuaipai(left)+[pivort]+kuaipai(right)
        return kuaipai(arr)[:k]

快排标准写法
在这里插入图片描述
排序直接操作原始数组,
程序一定要先从右端开始遍历,因为两端遍历最终停下的条件肯定是相遇的时候,如果左端先移动,则最后停下时的数值肯定比基数大,若将这个 数字与基数交换,则基数左边的数字就不是全部比基数小了,程序运行就不正确了。
每次找到一个分割点,当k-1是分割点时,前k-1个数即为要求

class Solution:
    def smallestK(self, arr: List[int], k: int) -> List[int]:
        if k==0:
            return []
        #快排
        def helper(left,right,k):
            tmp=arr[left]
            i,j=left,right
            while i<j:
                while i<j and arr[j]>=tmp:
                    j-=1
                arr[i]=arr[j]
                while i<j and arr[i]<=tmp:
                    i+=1
                arr[j]=arr[i]
            arr[i]=tmp
            #分隔点是前k个最小数,则返回
            if i==k-1:
                return 
            elif i>k-1:
                helper(left,i-1,k)
            else:
                helper(i+1,right,k)
        helper(0,len(arr)-1,k)
        return arr[:k]

23 合并K个排序链表
在这里插入图片描述
法一:暴力法
所有数据放到一个数组里,重新进行排序后构造链表

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

class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        if not lists:
            return 
        ans=[]
        dummy=ListNode(0)
        cur=dummy
        for lst in lists:
            while lst:
                ans.append(lst.val)
                lst=lst.next
        ans.sort()
        for i in range(len(ans)):
            cur.next=ListNode(ans[i])
            cur=cur.next
        return dummy.next

法二:分治法 类似148
将一个规模为N的问题,分解成K个规模较小的子问题,这些子问题相互独立且月原问题性质相同。 求解出子问题的解,合并得到原问题的解。

首先实现2个有序链表的合并,而后按照归并排序的思路,持续对K个链表进行两两排序,如果是奇数个,则最后一个链表本轮不排序直接进入下一轮,直至最终只剩下一个链表结束。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
import heapq
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        if len(lists)==0:
            return 
        if len(lists)==1:
            return lists[0]
        mid=len(lists)//2
        #分治时每次合并两个链表
        return self.merge(self.mergeKLists(lists[:mid]),self.mergeKLists(lists[mid:]))
    def merge(self,node_a,node_b):
        dummry=ListNode(0)
        cur=dummry
        while node_a and node_b:
            if node_a.val<node_b.val:
                cur.next=ListNode(node_a.val)
                node_a=node_a.next
            else:
                cur.next=ListNode(node_b.val)
                node_b=node_b.next
            cur=cur.next
            # 有一方的next的为空,就没有比较的必要了,直接把不空的一边加入到结果的 next 上
        if node_a:
            cur.next=node_a
        if node_b:
            cur.next=node_b
        return dummry.next

1382 将二叉搜索树变平衡
在这里插入图片描述
利用二叉搜索树性质
先中序遍历获取二叉搜索树的数据(递增数列),然后构造平衡二叉树,将数组从中点一分为二,左边是左子树,右边是右子树,中点是根节点

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def balanceBST(self, root: TreeNode) -> TreeNode:
        self.res=[]
        self.tree(root)
        return self.struct_bst(self.res)

    def struct_bst(self,nums):
        if len(nums)==0:
            return
        if len(nums)==1:
            return TreeNode(nums[0])
        mid=len(nums)//2
        newroot=TreeNode(nums[mid])
        newroot.left=self.struct_bst(nums[:mid])
        newroot.right=self.struct_bst(nums[mid+1:])
        return newroot

    def tree(self,head):
        if not head:
            return 
        self.tree(head.left)
        self.res.append(head.val)
        self.tree(head.right)
        return self.res

1038 从二叉搜索树到更大和树
在这里插入图片描述
在这里插入图片描述
利用二叉搜索树中序遍历是递增序列
在这里插入图片描述
反向中序遍历即可,并把每次的节点值进行累加,就能得到最终的累加树。而且这样保证了我们对每个节点只访问了一次。
从右子树开始中序遍历,修改每个节点为他之前节点的和加上节点自身的值

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def __init__(self):
        self.sum=0
    def bstToGst(self, root: TreeNode) -> TreeNode:
        if not root:
            return 
        self.bstToGst(root.right)
        self.sum+=root.val
        root.val=self.sum
        self.bstToGst(root.left)
        return root

538 把二叉搜索树转换为求和树
在这里插入图片描述
反向中序遍历

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def __init__(self):
        self.sum=0
    def convertBST(self, root: TreeNode) -> TreeNode:
        if not root:
            return
        self.convertBST(root.right)
        self.sum+=root.val
        root.val=self.sum
        self.convertBST(root.left)
        return root

1373 二叉搜索子树的最大键值和
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

搜索数的判断在每个节点的逻辑为,判断左子树最大值是否小于当前节点(或者左子树不存在),右子树的最小值是否大于当前节点(或者右子树不存在),若满足则该子树为二叉搜索树。

分解子问题,对每个子树分别求递归所需的5个子问题:
1.BST 子树最大节点和(即最终问题答案,用一个全局变量在递归中逐个检查每个节点)
2.以当前节点为root的子树是否是BST
3.BST子树的最小值
4.BST子树的最大值
5.以当前节点为root的子树对应的节点之和,若非BST,则回 0,

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def maxSumBST(self, root: TreeNode) -> int:
        self.maxsum=0
        self.isbst(root)
        return self.maxsum
    def isbst(self,node):
        if not node:
            #空值都可以作为二叉搜索树的左右节点
            isbst,max_value,min_value,sum_val=True,float('-inf'),float('inf'),0
            return isbst,max_value,min_value,sum_val
        isbst_l,max_value_l,min_value_l,sum_val_l=self.isbst(node.left)
        isbst_r,max_value_r,min_value_r,sum_val_r=self.isbst(node.right)
        #判断以node为根节点的树是否是二叉搜索树
        #左右子树都是BST且左子树最大值<根节点<右子树最小值
        if isbst_l and isbst_r and max_value_l<node.val<min_value_r:
#是二叉搜索树,更新该搜索树最大值,最小值,节点和,向上传递
            max_value=max(node.val,max_value_r)
            min_value=min(node.val,min_value_l)
            sum_val=sum_val_l+sum_val_r+node.val
            isbst=True
            self.maxsum=max(self.maxsum,sum_val)
        else:
            #不是二叉搜索树,则将最大值,最小值设置的不可能满足条件
            isbst=False
            max_value,min_value=float('inf'),float('-inf')
            sum_val=0
        return isbst,max_value,min_value,sum_val

938 二叉搜索树的范围和
在这里插入图片描述
在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def rangeSumBST(self, root: TreeNode, L: int, R: int) -> int:
        self.res=0
        def dfs(node,l,r):
            if not node:
                return 
            dfs(node.left,l,r)
            if node.val>=l and node.val<=r:
                self.res+=node.val
            dfs(node.right,l,r)
            return self.res
        return dfs(root,L,R)

623 在二叉树中增加一行
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def addOneRow(self, root: TreeNode, v: int, d: int) -> TreeNode:
        if d==1:
            newroot=TreeNode(v)
            newroot.left=root
            return newroot
        stack=[root]
        depth=0
        while stack:
            depth+=1
            for _ in range(len(stack)):
                node=stack.pop(0)
                if depth==d-1:
                    if node.left:
                    #保存节点原来的左子树
                        left=node.left
                        newl=TreeNode(v)
                        node.left=newl
                        newl.left=left
                    else:
                        newl=TreeNode(v)
                        node.left=newl
                    if node.right:
                    #保存节点原来的右子树
                        right=node.right
                        newr=TreeNode(v)
                        node.right=newr
                        newr.right=right
                    else:
                        newr=TreeNode(v)
                        node.right=newr
                else:
                #正常添加左右节点
                    if node.left:
                        stack.append(node.left)
                    if node.right:
                       stack.append(node.right)
        return root

563 二叉树的坡度
在这里插入图片描述
递归:在任何结点调用该函数,都会返回当前结点下面(包括其自身)的结点和。借助于任何结点的左右子结点的这一和值,我们可以直接获得该结点所对应的坡度。

class Solution:
    def findTilt(self, root: TreeNode) -> int:
        self.po=0
        def helper(root):
            if not root:
                return 0
             #当前节点左子树的和
            left=helper(root.left)
            #当前节点右子树的和
            right=helper(root.right)
            #坡度
            self.po+=abs(left-right)
            #当前节点下面(包括自身)的节点和,向上传递
            return left+right+root.val
        helper(root)
        return self.po

145 二叉树的后序遍历
在这里插入图片描述
迭代实现:
在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        stack=[]
        res=[]
        node=root
        while stack or node:
            while node:
                #第一次入栈的事根节点
                stack.append(node)
                #判断当前节点的左子树是否存在,若存在则持续左下行,若不存在就转向右子树
                node=node.left if node.left else node.right
            #到达最左叶子结点
            node=stack.pop()
            res.append(node.val)
            #判断该节点是父节点的左子树还是右子树
            if stack and stack[-1].left==node:
                #是左子树则转去访问右子树,此时栈顶元素为Node的父节点
                node=stack[-1].right
            else:
                #是右子树则退栈,接下来访问栈顶元素
                node=None
        return res

590 N叉树的后序遍历
在这里插入图片描述
迭代:

"""
# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution:
    def postorder(self, root: 'Node') -> List[int]:
        if not root:
            return []
        stack=[root]
        node=root
        res=[]
        while stack:
            root=stack.pop()
            if root:
                res.append(root.val)
            for c in root.children:
                stack.append(c)
        return res[::-1]

递归:

class Solution:
    def postorder(self, root: 'Node') -> List[int]:
        if not root:
            return []
        self.res=[]
        def dfs(root):
            if not root:
                return
            for i in root.children:
                dfs(i)
            self.res.append(root.val)
            return self.res
        dfs(root)
        return self.res

589 N叉树前序遍历:
在这里插入图片描述
递归:

"""
# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution:
    def preorder(self, root: 'Node') -> List[int]:
        if not root:
            return []
        self.res=[]
        def dfs(root):
            if not root:
                return 
            self.res.append(root.val)
            for i in root.children:
                dfs(i)
            return self.res
        dfs(root)
        return self.res

迭代:

class Solution:
    def preorder(self, root: 'Node') -> List[int]:
        if not root:
            return []
        res=[]
        stack=[root]
        while stack:
            root=stack.pop()
            res.append(root.val)
            if root.children:
                for i in root.children[::-1]:
                    stack.append(i)
        return res
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值