python学习日志2021-01-27

堆盘子

设想有一堆盘子,堆太高可能会倒下来。因此,在现实生活中,盘子堆到一定高度时,我们就会另外堆一堆盘子。请实现数据结构SetOfStacks,模拟这种行为。SetOfStacks应该由多个栈组成,并且在前一个栈填满时新建一个栈。此外,SetOfStacks.push()和SetOfStacks.pop()应该与普通栈的操作方法相同(也就是说,pop()返回的值,应该跟只有一个栈时的情况一样)。 进阶:实现一个popAt(int index)方法,根据指定的子栈,执行pop操作。

当某个栈为空时,应当删除该栈。当栈中没有元素或不存在该栈时,pop,popAt 应返回 -1.

要点在于处理边界情形,利用好list中的pop()和append()方法。代码如下:

class StackOfPlates:
    def __init__(self, cap: int):
        self.cap = cap
        self.array = []

    def push(self, val: int) -> None:
        # 处理边界情况:cap == 0 不让push
        if self.cap == 0:
            return

        if not self.array or len(self.array[-1]) >= self.cap:
            self.array.append([val])
        else:
            self.array[-1].append(val)

    def pop(self) -> int:
        val = -1
        if self.array and self.array[-1]:
            val = self.array[-1].pop()
            if not self.array[-1]: self.array.pop()
        return val

    def popAt(self, index: int) -> int:
        val = -1
        if len(self.array) >= index + 1:
            val = self.array[index].pop()
            if not self.array[index]: self.array.pop(index)
        return val

栈排序

辅助栈解法

维护两个单调递减的栈,并且stack的最大元素要小于helpstack的最小元素,即helpstack的栈顶>=stack[0]
优先考虑stack,
如果val<=self.stack[-1],直接添加即可
如果val>self.stack[-1],考虑stack[0]与val的关系,
如果stack[0]>val,左边删除stack加入到helpstack
如果stack[0]<val,考虑与helpstack的关系,

如果stack为空再考虑helpstack:
与上面同理

最后如果都为空,直接添加到stack即可

总之,每一次push操作均要保证两点:
1、两个单调递减的栈
2、helpstack[-1]>=stack[0]

class SortedStack:

    def __init__(self):
        from collections import deque
        #维持两个单调递减的栈,并且stack的最大元素要小于helpstack的最小元素,即helpstack的栈顶>=stack[0]
        self.helpstack = deque()
        self.stack = deque()
    def push(self, val: int) -> None:
        if self.stack:
            if val <= self.stack[-1]:
                self.stack.append(val)
                return
            
            # 如果val>self.stack[-1],考虑stack[0]与val的关系
            while self.stack and val < self.stack[0]:
                temp = self.stack.popleft()
                self.helpstack.append(temp)
            
            # 如果val>=self.stack[0],考虑helpstack[-1]与val的关系
            while self.helpstack and val > self.helpstack[-1]:
                temp = self.helpstack.pop()
                self.stack.appendleft(temp)
            
            self.stack.appendleft(val)
        elif self.helpstack:
            while self.helpstack and val > self.helpstack[-1]:
                temp = self.helpstack.pop()
                self.stack.appendleft(temp)
            self.helpstack.append(val)
        else:
            self.stack.append(val)
    def pop(self) -> None:
        if self.stack:
            self.stack.pop()
        elif self.helpstack:
            self.helpstack.pop()
        else:
            return
    def peek(self) -> int:
        if self.stack:
            return self.stack[-1]
        elif self.helpstack:
            return self.helpstack[-1]
        else:
            return -1
    def isEmpty(self) -> bool:
        return len(self.stack)+len(self.helpstack)==0

节点间通路

节点间通路。给定有向图,设计一个算法,找出两个节点之间是否存在一条路径。

邻接表和BFS(广度优先搜索)算法

class Solution:
    def findWhetherExistsPath(self, n: int, graph: List[List[int]], start: int, target: int) -> bool:
        # 构建邻接表
        link_table = [[] for i in range(n)]
        for edge in graph:
            link_table[edge[0]].append(edge[1])
        visited = [0]*n
        # BFS
        que = [start]
        while que:
            cur_node = que.pop()
            if target in link_table[cur_node]:
                return True
            for node in link_table[cur_node]:
                if visited[node] == 0:
                    que.insert(0, node)
            visited[cur_node] = 1
        return False

邻接表和DFS(深度优先搜索)算法

class Solution:
    def findWhetherExistsPath(self, n: int, graph: List[List[int]], start: int, target: int) -> bool:
        # 邻接表
        edges = collections.defaultdict(list)
        for i in graph:
            edges[i[0]].append(i[1])
        # DFS
        def DFS(start, target, visited):
            if start == target:
                return True
            if visited[start]:
                return False
            visited[start] = True
            judge = False
            for i in edges[start]:
                if not visited[i]:
                    judge = judge or DFS(i, target, visited)
            return judge
        visited = [False]*n
        return DFS(start, target, visited)

BFS算法和DFS算法相比较,两者内存消耗相近,但DFS算法运行时间较短。

合法二叉搜索树

二叉搜索树,又称二叉排序树,它的特点是它的中序遍历一定是一个单调递增数列。

class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        nodes =[]
        def search(root):
            if root:
                search(root.left)
                nodes.append(root.val)
                search(root.right)
        search(root)
        return nodes == sorted(set(nodes))

首个共同祖先

设计并实现一个算法,找出二叉树中某两个节点的第一个共同祖先。不得将其他的节点存储在另外的数据结构中。注意:这不一定是二叉搜索树。

递归解法

  • 假设我们从跟结点开始,采用 DFS 向下遍历,如果当前结点到达叶子结点下的空结点时,返回空;如果当前结点为 p 或 q 时,返回当前结点;
  • 这样,当我们令 left = self.lowestCommonAncestor(root.left, p, q) 时,如果在左子树中找到了 p 或 q,left 会等于 p 或 q,同理,right 也是一样;
  • 然后我们进行判断:如果 left 为 right 都不为空,则为情况 1;如果 left 和 right 中只有一个不为空,说明这两个结点在子树中,则根节点到达子树再进行寻找。

代码如下:

class Solution:
    def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
        if not root or root == p or root == q:
            return root
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)
        if left and right:
            return root
        return left if left else right

二叉搜索树序列

递归解法

使用一个queue存储下个所有可能的节点,然后选择其中一个作为path的下一个元素,递归直到queue元素为空,将对应的path加入结果中。由于二叉搜索树没有重复元素, 而且每次递归的使用元素的顺序都不一样, 所以自动做到了去重。

class Solution:
    def BSTSequences(self, root: TreeNode) -> List[List[int]]:
        if not root:
            return [[]]
        res = []
        def findPath(cur, q, path):
            if cur.left:
                q.append(cur.left)
            if cur.right:
                q.append(cur.right)
            if not q:
                res.append(path)
                return
            for i, nex in enumerate(q):
                newq = q[:i] + q[i + 1:]
                findPath(nex, newq, path + [nex.val])
        findPath(root, [], [root.val])
        return res

检查子树

检查子树。你有两棵非常大的二叉树:T1,有几万个节点;T2,有几万个节点。设计一个算法,判断 T2 是否为 T1 的子树。

如果 T1 有这么一个节点 n,其子树与 T2 一模一样,则 T2 为 T1 的子树,也就是说,从节点 n 处把树砍断,得到的树与 T2 完全相同。

双重dfs解法

第一重:在 t1 中找到 t2 的起点。先判断 t1 当前节点,如果不对就判断 t1 左子树和 t1 右子树。
第二重:从找到的起点开始判断剩下的点,t1 和 t2 同步左右子树搜索。

class Solution:
    def checkSubTree(self, t1: TreeNode, t2: TreeNode) -> bool:
        if not t1:
            return not t2
        if not t2:
            return True
        return self.dfs(t1, t2) or self.checkSubTree(t1.left, t2) or self.checkSubTree(t1.right, t2)

    def dfs(self, t1, t2):
        if not t2:
            return True
        elif not t1:
            return False
        elif t1.val != t2.val:
            return False
        else:
            return self.dfs(t1.left, t2.left) and self.dfs(t1.right, t2.right)

求和路径

递归解法

给定一棵二叉树,其中每个节点都含有一个整数数值(该值或正或负)。设计一个算法,打印节点数值总和等于某个给定值的所有路径的数量。注意,路径不一定非得从二叉树的根节点或叶节点开始或结束,但是其方向必须向下(只能从父节点指向子节点方向)。

pathSum所求的是从root节点及以下节点开始的路径数,而path函数所求的只是从root节点开始的路径数,利用递归方法,代码如下:

class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> int:
        if not root:
            return 0
        return self.path(root,sum)+self.pathSum(root.right,sum)+self.pathSum(root.left,sum)
    def path(self, root, sum):
        if not root:
            return 0
        res = 0
        if root.val == sum:
            res += 1
        res += self.path(root.left, sum-root.val)
        res += self.path(root.right, sum-root.val)
        return res 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值