【leetcode】树and递归

题目1

【简单】路径总和

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

示例:
给定如下二叉树,以及目标和 sum = 22,

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1

返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2

 

解答

有两种思想:递归与循环.
递归:参照递归的4个步骤:1.确定函数功能;2.递推公式,重要,只要把想出来了,就成功了一半;3.终止条件,通过举例子方式归纳得到.4.时空复杂度. 详见代码注释

循环:方法一:可以通过两个list交替循环,这个比较通用,比如计算树深度,打印树等任务.
方法二:通过一个stack的pop操作来实现循环.

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

class Solution:
    # 函数功能:输入一个root/sum,判断是否存在
    # 递推公式:hasPathSum(root,sum) = hasPathSum(root.left,sum-root.val) or hasPathSum(root.left,sum-root.val)
    # 终止条件:if not root: return False;if 是叶节点 and 值等于sum,return True
    # 复杂度: O(N);O(logN)
    # 只遍历左子树,右子树
    def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        if not root:
            return False
        if not root.left and not root.right and root.val == sum:
            return True
        left = self.hasPathSum(root.left,sum-root.val)
        right = self.hasPathSum(root.right,sum-root.val)
        return left or right

class Solution:
    # 循环.通过两个list进行交替
    # def hasPathSum(self,root,sum):
    #     if not root:
    #         return False
    #     curLayerNode = [(root,sum)]
    #     while curLayerNode:
    #         nextLayerNode = []
    #         for (node,val) in curLayerNode:
    #             if not node.left and not node.right and node.val == val:
    #                 return True
    #             if node.left:
    #                 nextLayerNode.append((node.left,val-(node.val)))
    #             if node.right:
    #                 nextLayerNode.append((node.right,val-(node.val)))
    #         curLayerNode = nextLayerNode
    #     return False

    #循环.通过一个stack的pop进行交替
    def hasPathSum(self,root,sum):
        if not root:
            return False
        stack = [(root,sum)]
        while stack:
            node,val = stack.pop()
            if not node.left and not node.right and node.val == val:
                return True
            if node.right:
                stack.append((node.right,val-node.val))
            if node.left:
                stack.append((node.left,val-node.val))
        return False



链接:https://leetcode-cn.com/problems/path-sum/solution/shu-de-di-gui-yu-xun-huan-de-an-li-zhi-yi-by-zhang/

 

题目2

【简单】二叉树的最小深度

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明: 叶子节点是指没有子节点的节点。

示例:

给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回它的最小深度  2.

 

解答

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

# 递归解法
class Solution:
# 递推公式:minDepth(root) = min(self.minDepth(root的子节点), min_depth)
# 终止条件:if not root: return 0;if 没有子节点,return 1
    def minDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if not root:
            return 0

        children = [root.left, root.right]
        # if we're at leaf node
        if not any(children):
            return 1

        min_depth = float('inf')
        for c in children:
            if c:
                min_depth = min(self.minDepth(c), min_depth)
        return min_depth + 1


class Solution:
    def minDepth(self, root: TreeNode) -> int:
        # 利用栈,记录深度
        if not root:
            return 0
        min_depth = 1
        stack = [(root,min_depth)]
        while stack:
            node,val = stack.pop()
            if not node.left and not node.right:
                if min_depth == 1:
                    min_depth = val
                else:
                    min_depth = min(min_depth,val)
            if node.right:
                stack.append((node.right,val+1))
            if node.left:
                stack.append((node.left,val+1))
        return min_depth

 

题目3

【简单】最长同值路径

给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。

注意:两个节点之间的路径长度由它们之间的边数表示。

示例 1:

输入:

              5
             / \
            4   5
           / \   \
          1   1   5

输出:

2

示例 2:

输入:

              1
             / \
            4   5
           / \   \
          4   4   5

输出:

2

解答

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

class Solution:
    def longestUnivaluePath(self, root: TreeNode) -> int:
        self.ans = 0

        def arrow_length(node):
            if not node: return 0
            left_length = arrow_length(node.left)
            right_length = arrow_length(node.right)
            left_arrow = right_arrow = 0
            if node.left and node.left.val == node.val:
                left_arrow = left_length + 1
            if node.right and node.right.val == node.val:
                right_arrow = right_length + 1
            self.ans = max(self.ans, left_arrow + right_arrow)
            return max(left_arrow, right_arrow)

        arrow_length(root)
        return self.ans

 

【补充】

算法题之递归调用

递归求解算法题有三个要素:(这里以n的阶乘为例)

1、函数功能

// 算 n 的阶乘(假设n不为0)
int f(int n){
 /**/
}

2、终止条件

所谓递归,就是会在函数内部代码中,调用这个函数本身,所以必须要找出递归的结束条件,不然的话,会一直调用自己,进入无限循环。也就是说,需要找出当参数为啥时,递归结束,之后把结果返回。

// 算 n 的阶乘(假设n不为0)
int f(int n){
    if(n <= 2){
        return n;
    }
}

3、递归公式

不断缩小参数的范围,例如,f(n) 这个范围比较大,我们可以让 f(n) = n * f(n-1)

// 算 n 的阶乘(假设n不为0)
int f(int n){
    if(n <= 2){
       return n;
    }
    // 把 f(n) 的等价操作写进去
    return f(n-1) * n;
}

 

例: 斐波那契数

斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

终止条件:

F(0) = 0,   F(1) = 1

递归公式:
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.

给定 N,计算 F(N)。

class Solution:
    def fib(self, N: int) -> int:
        if N == 0:
            return 0
        elif N == 1:
            return 1
        else:
            return self.fib(N-1) + self.fib(N-2)

 

例:爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

终止条件:

F(1) = 1, F(2)=2

递归公式:

第一种跳法:第一次跳了1个台阶,那么还剩下n-1个台阶还没跳,剩下的n-1个台阶的跳法有F(N-1)种。

第二种跳法:第一次跳了2个台阶,那么还剩下n-2个台阶还没,剩下的n-2个台阶的跳法有F(N-2)种。

F(N) =F(N-1)+F(N-2)

class Solution:
    def climbStairs(self, n: int) -> int:
        if n == 1:
            return 1
        elif n == 2:
            return 2
        else:
            return self.climbStairs(n-1) + self.climbStairs(n-2)

 

例:反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

终止条件:

当链表只有一个节点,或者如果是空表的话,你应该知道结果吧?直接啥也不用干,直接把 head 返回

递归公式:

以下面head->1->2->3->4为例

已经定义了 reverseLis t函数的功能可以把一个单链表反转,所以,我们对 2->3->4反转之后的结果应该是这样:

把 2->3->4 递归成 4->3->2。但1 这个节点我们并没有去碰它,所以 1 的 next 节点仍然是连接这 2。

接下来只需要把节点 2 的 next 指向 1,然后把 1 的 next 指向 null,即通过改变 newList 链表之后的结果如下:

也就是说,reverseList(head) 等价于  reverseList(head.next) + 改变一下1,2两个节点的指向

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

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        # 1.递归结束条件
        if head is None or head.next is None:
              return head
        # 递归反转 子链表
        newList = self.reverseList(head.next)
        # 改变 1,2节点的指向。
        # 通过 head.next获取节点2
        t1  = head.next
        # 让 2 的 next 指向 2
        t1.next = head
        # 1 的 next 指向 null
        head.next = None
        # 把调整之后的链表返回。
        return newList

 


 

参考:

算法练习题之递归调用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章