剑指offer 刷题 十九 搜索与回溯(64 68-I 68-II)

剑指 Offer 64. 求1+2+…+n
求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
在这里插入图片描述
我用了if的代码:

 def sumNums(self, n: int) -> int:
        if n == 1: return 1
        return n + self.sumNums(n-1)

下面是大佬没有用if的思路和代码。。。。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
根据大佬思路,修改的代码,写的不对。。。

def sumNums(self, n: int) -> int:
        res = n > 1 and n + self.sumNums(n-1)
        res += 1 
        return res

还是看下大佬的代码吧。。。
大佬代码:

class Solution:
    def __init__(self):
        self.res = 0
    def sumNums(self, n: int) -> int:
        n > 1 and self.sumNums(n - 1)
        self.res += n
        return self.res

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

在这里插入图片描述
DFS代码:自己写的,把路径找出来,然后求路径的交集最后一个。但是我发现它这个函数最后需要return一个TreeNode类型。所以我的代码最后老报错。

def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        res, path = [], []

        def dfs(root):
            if not root: return
            path.append(root.val)
            if root.left: dfs(root.left)
            if root.right: dfs(root.right)
            if not root.left and not root.right: res.append(list(path))
            path.pop()

        dfs(root)
        
        res_p, res_q = [], []
        for path in res:
            for i in range(len(path)):
                if path[i] == p.val:
                    res_p = path[:i]
                if path[i] == q.val:
                    res_q = path[:i]

        ([i for i in res_p if i in res_q][-1])

看下大佬的思路和代码吧。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
照着大佬的思路,写出来的代码:

 def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        queue = collections.deque()
        queue.append(root)
        while queue:
            node = queue.popleft()
            if node.val < p.val and node.val < q.val: queue.append(node.right)
            if node.val > p.val and node.val > q.val: queue.append(node.left)
            if node.val > p.val and node.val < q.val: return node
            elif node.val < p.val and node.val > q.val: return node
            if node.val == p.val: return node
            if node.val == q.val: return node

在这里插入图片描述
接下来是大佬的代码:

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        while root:
            if root.val < p.val and root.val < q.val: # p,q 都在 root 的右子树中
                root = root.right # 遍历至右子节点
            elif root.val > p.val and root.val > q.val: # p,q 都在 root 的左子树中
                root = root.left # 遍历至左子节点
            else: break
        return root

在这里插入图片描述

优化:若可保证 p.val < q.valp.val<q.val ,则在循环中可减少判断条件。

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if p.val > q.val: p, q = q, p # 保证 p.val < q.val
        while root:
            if root.val < p.val: # p,q 都在 root 的右子树中
                root = root.right # 遍历至右子节点
            elif root.val > q.val: # p,q 都在 root 的左子树中
                root = root.left # 遍历至左子节点
            else: break
        return root

在这里插入图片描述
总结:学习了BFS便利到下一层,可以不用queue,而是直接通过root=root.left/root.right实现,妙啊。另外再判断公共祖先的时候,p和q位置可以交换,因为他们的爹只有一个。所以第二种优化方法在速度上有了明显提升,但是空间复杂度为什么会降低那么多,我没想通。

在这里插入图片描述
照着大佬思路写的代码,其实不是很明白。。。

def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
            if root.val < p.val and root.val < q.val:
                return self.lowestCommonAncestor(root.right, p, q)
            if root.val > p.val and root.val > q.val:
                return self.lowestCommonAncestor(root.left, p, q)
            return root

在这里插入图片描述
应该是用的DFS的思想,速度比BFS要快。
下面是大佬代码,和我写的一样:

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if root.val < p.val and root.val < q.val:
            return self.lowestCommonAncestor(root.right, p, q)
        if root.val > p.val and root.val > q.val:
            return self.lowestCommonAncestor(root.left, p, q)
        return root

剑指 Offer 68 - II. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

在这里插入图片描述
这题是我之前理解的68-I的题,还是没有想到node节点如何存储问题。我觉得应该还是通过递归的方法来解决。直接看大佬题解吧:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里的判断条件和我想的一样。考虑通过递归对二叉树进行先序遍历,当遇到节点 p 或 q 时返回。从底至顶回溯,当节点 p, q 在节点 root 的异侧时,节点 root 即为最近公共祖先,则向上返回 root。
在这里插入图片描述
红线部分理解看下图:
在这里插入图片描述
接下来是全部的动态展示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
看完动态展示,才能更好的理解递归和回溯。
在这里插入图片描述
根据大佬思路,写的代码:

def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
        if not root: return None
        if root.val == p.val: return root
        elif root.val == q.val: return root
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)
        if not left and not right: return None
        elif left and right: return root
        elif not left and right: return right
        elif left and not right: return left
        

在这里插入图片描述
BFS其实速度很快。
下面是大佬的代码:太精简了。。。。

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 not left: return right
        if not right: return left
        return root
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值