最新程序员必备的基本算法:递归详解,连续四年百度Java岗必问面试题

面试题总结

其它面试题(springboot、mybatis、并发、java中高级面试总结等)

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

2.寻找递归终止条件

递归的一个典型特征就是必须有一个终止的条件,即不能无限循环地调用本身。所以,用递归思路去解决问题的时候,就需要寻找递归终止条件是什么。比如阶乘问题,当n=1的时候,不用再往下递归了,可以跳出循环啦,n=1就可以作为递归的终止条件,如下:

//n的阶乘(n为大于0的自然数)

int factorial (int n){

if(n==1){

return 1;

}

}

复制代码

3.递推函数的等价关系式

递归的本义,就是原问题可以拆为同类且更容易解决的子问题,即原问题和子问题都可以用同一个函数关系表示。递推函数的等价关系式,这个步骤就等价于寻找原问题与子问题的关系,如何用一个公式把这个函数表达清楚。阶乘的公式就可以表示为 f(n) = n * f(n-1), 因此,阶乘的递归程序代码就可以写成这样,如下:

int factorial (int n){

if(n==1){

return 1;

}

return n * factorial(n-1);

}

复制代码

注意啦,不是所有递推函数的等价关系都像阶乘这么简单,一下子就能推导出来。需要我们多接触,多积累,多思考,多练习递归题目滴~

leetcode案例分析

来分析一道leetcode递归的经典题目吧~

原题链接在这里哈:leetcode-cn.com/problems/in…

题目: 翻转一棵二叉树。

输入:

4

/ \

2 7

/ \ / \

1 3 6 9

复制代码

输出:

4

/ \

7 2

/ \ / \

9 6 3 1

复制代码

我们按照以上递归解题的三板斧来:

1. 定义函数功能

函数功能(即这个递归原问题是),给出一颗树,然后翻转它,所以,函数可以定义为:

//翻转一颗二叉树

public TreeNode invertTree(TreeNode root) {

}

/**

  • Definition for a binary tree node.

  • public class TreeNode {

  • int val;
    
  • TreeNode left;
    
  • TreeNode right;
    
  • TreeNode(int x) { val = x; }
    
  • }

*/

复制代码

2.寻找递归终止条件

这棵树什么时候不用翻转呢?当然是当前节点为null或者当前节点为叶子节点的时候啦。因此,加上终止条件就是:

//翻转一颗二叉树

public TreeNode invertTree(TreeNode root) {

if(root==null || (root.left ==null && root.right ==null)){

return root;

}

}

复制代码

3. 递推函数的等价关系式

原问题之你要翻转一颗树,是不是可以拆分为子问题,分别翻转它的左子树和右子树?子问题之翻转它的左子树,是不是又可以拆分为,翻转它左子树的左子树以及它左子树的右子树?然后一直翻转到叶子节点为止。嗯,看图理解一下咯~

首先,你要翻转根节点为4的树,就需要翻转它的左子树(根节点为2)和右子树(根节点为7)。这就是递归的的过程啦

然后呢,根节点为2的树,不是叶子节点,你需要继续翻转它的左子树(根节点为1)和右子树(根节点为3)。因为节点1和3都是叶子节点了,所以就返回啦。这也是递归的的过程~

同理,根节点为7的树,也不是叶子节点,你需要翻转它的左子树(根节点为6)和右子树(根节点为9)。因为节点6和9都是叶子节点了,所以也返回啦。

左子树(根节点为2)和右子树(根节点为7)都被翻转完后,这几个步骤就归来,即递归的归过程,翻转树的任务就完成了~

显然,递推关系式就是:

invertTree(root)= invertTree(root.left) + invertTree(root.right);

复制代码

于是,很容易可以得出以下代码:

//翻转一颗二叉树

public TreeNode invertTree(TreeNode root) {

if(root==null || (root.left ==null && root.right ==null){

return root;

}

//翻转左子树

TreeNode left = invertTree(root.left);

//翻转右子树

TreeNode right= invertTree(root.right);

}

复制代码

这里代码有个地方需要注意,翻转完一棵树的左右子树,还要交换它左右子树的引用位置。

root.left = right;

root.right = left;

复制代码

因此,leetcode这个递归经典题目的终极解决代码如下:

class Solution {

public TreeNode invertTree(TreeNode root) {

if(root==null || (root.left ==null && root.right ==null)){

return root;

}

//翻转左子树

TreeNode left = invertTree(root.left);

//翻转右子树

TreeNode right= invertTree(root.right);

//左右子树交换位置~

root.left = right;

root.right = left;

return root;

}

}

复制代码

拿终极解决代码去leetcode提交一下,通过啦~

递归存在的问题

  • 递归调用层级太多,导致栈溢出问题

  • 递归重复计算,导致效率低下

栈溢出问题

  • 每一次函数调用在内存栈中分配空间,而每个进程的栈容量是有限的。

  • 当递归调用的层级太多时,就会超出栈的容量,从而导致调用栈溢出。

  • 其实,我们在前面小节也讨论了,递归过程类似于出栈入栈,如果递归次数过多,栈的深度就需要越深,最后栈容量真的不够咯

代码例子如下:

/**

  • 递归栈溢出测试

*/

public class RecursionTest {

public static void main(String[] args) {

sum(50000);

}

private static int sum(int n) {

if (n <= 1) {

return 1;

}

return sum(n - 1) + n;

}

}

复制代码

运行结果:

Exception in thread “main” java.lang.StackOverflowError

at recursion.RecursionTest.sum(RecursionTest.java:13)

复制代码

怎么解决这个栈溢出问题?首先需要优化一下你的递归,真的需要递归调用这么多次嘛?如果真的需要,先稍微调大JVM的栈空间内存,如果还是不行,那就需要弃用递归,优化为其他方案咯~

重复计算,导致程序效率低下

我们再来看一道经典的青蛙跳阶问题:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

绝大多数读者朋友,很容易就想到以下递归代码去解决:

class Solution {

public int numWays(int n) {

if (n == 0){

return 1;

}

if(n <= 2){

return n;

}

return numWays(n-1) + numWays(n-2);

}

}

复制代码

但是呢,去leetcode提交一下,就有问题啦,超出时间限制了

为什么超时了呢?递归耗时在哪里呢?先画出递归树看看:

结局:总结+分享

看完美团、字节、腾讯这三家的一二三面试问题,是不是感觉问的特别多,可能咱们真的又得开启面试造火箭、工作拧螺丝的模式去准备下一次的面试了。

开篇有提及我可是足足背下了Java互联网工程师面试1000题,多少还是有点用的呢,换汤不换药,不管面试官怎么问你,抓住本质即可!能读到此处的都是真爱

  • Java互联网工程师面试1000题

image.png

而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的 《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。

  • 程序员代码面试指南–IT名企算法与数据结构题目最优解

image.png

  • 其余像设计模式,建议可以看看下面这4份PDF(已经整理)

image.png

  • 更多的Java面试学习笔记如下,关于面试这一块,我额外细分出Java基础-中级-高级开发的面试+解析,以及调优笔记等等等。。。

image.png

以上所提及的全部Java面试学习的PDF及笔记,如若皆是你所需要的,那么都可发送给你!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

码面试指南–IT名企算法与数据结构题目最优解**

[外链图片转存中…(img-HS1rnHgY-1715678608552)]

  • 其余像设计模式,建议可以看看下面这4份PDF(已经整理)

[外链图片转存中…(img-wi973K0E-1715678608552)]

  • 更多的Java面试学习笔记如下,关于面试这一块,我额外细分出Java基础-中级-高级开发的面试+解析,以及调优笔记等等等。。。

[外链图片转存中…(img-MJByR5Fa-1715678608553)]

以上所提及的全部Java面试学习的PDF及笔记,如若皆是你所需要的,那么都可发送给你!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 18
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值