JAVA进步一点点--数据结构与算法(递归)

递归

我们递归的求解一个问题,在每层递归中应用如下三个步骤:

  1. 将问题划分为一些子问题,子问题的形式和原问题一样,只是规模更小
  2. 递归的解决子问题,当子问题足够小(初始值)时,即停止递归
  3. 将子问题的解合并成原问题的解
    斐波那契数列
    先来个简单题开个胃:https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof/
    按照上面的套路进行分析:
  4. 将问题划分为一些子问题 f(n) = f(n-1) + f(n-2) ,n-2>=0 则初始值是f(0) f(1)
  5. 子问题足够小(初始值),f(0) = 0 f(1) = 1
  6. 将子问题合并 递归本身就是在堆栈中保存调用,实现合并的过程。即return fib(n-1) + fib(n-2),递归调用到堆栈的过程
    public int fib(int n) {
		if (n == 0 ) {
			return 0;
		}
        if (n == 1){
            return 1;
        }
		return fib(n - 1) + fib(n - 2);
    }

687. 最长同值路径
来个中等的 https://leetcode-cn.com/problems/longest-univalue-path/

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

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

第一感觉,题没读懂,关键点认为是下面:

  • 两个节点间的路径是啥意思
  • 是否只有一条
  • 如何找到两个节点间的路径
  • 如果都相等会有什么特征,不等又有什么特征
    二叉树的基本知识可以看一下大神的博客:https://www.cnblogs.com/sunshineliulu/p/7775063.html
    根据题目意思可以明确看出节点间路径的意思,那么剩下的问题也基本好解答了。
  • 是否只有一条 ————根据二叉树特性,不走重复路线的话,就只有一条了,否则不是有环了吗
  • 如何找到两个节点间的路径————可以从根分别找到两个节点的路径,然后合并一下
  • 如果都相等会有什么特征,不等又有什么特征 ————合并后路径上的数都是一样的
    分析到这里,感觉更像是列出所有路径,然后去合并,而合并到哪个节点终止也很难说,这样将变成n!种可能,这也太难搞了吧。

我们尝试分析一下是否可以分解为子问题:
(1)路径本身就可以是一个二叉树,只是所有节点都少了一个边
(2)要找的路径必然包含两个相等的节点(父节点和子节点相等),并且可能还有很多个相等
(3)这样变成了对每个节点找向外延伸的最长,这样必然有子问题,例如5(0) - 5(1) - 5(2) - 5(3)- 5(4),我们找2向左延伸的最长,是5(1)向左延伸的最长+1;
代码还是不会写,对照答案进行分析流程,感觉流程有重复子问题,不知道是否可以用DP,欢迎大家留言讨论。
在这里插入图片描述在这里插入图片描述

        int ans;
    public int longestUnivaluePath(TreeNode root) {
        ans = 0;
        arrowLength(root);
        return ans;
    }
    public int arrowLength(TreeNode node) {
    //这里十分巧妙,将null直接返回0,满足了树的遍历条件
        if (node == null) return 0;
        //当前节点的最长依赖于左节点,也依赖于右节点,满足了后序遍历条件
        int left = arrowLength(node.left);
        int right = arrowLength(node.right);
        int arrowLeft = 0, arrowRight = 0;
        //先处理左,把左边的加进来
        if (node.left != null && node.left.val == node.val) {
            arrowLeft += left + 1;
        }
        //再处理右,把右边的加进来
        if (node.right != null && node.right.val == node.val) {
            arrowRight += right + 1;
        }
        //总长和ans对比,如果当前节点更长时,更新ans
        ans = Math.max(ans, arrowLeft + arrowRight);
        //返回当前节点的最长延伸
        return Math.max(arrowLeft, arrowRight);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值