Q.请写一段代码来计算给定文本内字符“A”的个数。分别用迭代和递归两种方式。
A.假设给定文本为”AAA rating”。迭代方式就很直观,如下:
public class Iteration { public int countA(String input) { if (input == null || input.length( ) == 0) { return 0; } int count = 0; for (int i = 0; i < input.length( ); i++) { if(input.substring(i, i+1).equals("A")){ count++; } } return count; } public static void main(String[ ] args) { System.out.println(new Iteration( ).countA("AAA rating")); // Ans.3 } }
接下来,递归方式的代码如下:
public class RecursiveCall { public int countA(String input) { // exit condition – recursive calls must have an exit condition if (input == null || input.length( ) == 0) { return 0; } int count = 0; //check first character of the input if (input.substring(0, 1).equals("A")) { count = 1; } //recursive call to evaluate rest of the input //(i.e. 2nd character onwards) return count + countA(input.substring(1)); } public static void main(String[ ] args) { System.out.println(new RecursiveCall( ).countA("AAA rating")); // Ans. 3 } }
递归比较难以理解,我们用下面的图来进行说明。
Q.理解递归需要了解哪些概念?
A. 可重入方法(re-entrant method)是可以安全进入的方法,即使同一个方法正在被执行,深入到同一个线程的调用栈里面也不会影响此次执行的安全性。一个非可重入方法则不是可以安全进入的。例如,加入写文件或者向文件中写入日志的方法不是可重入方法时,有可能会毁坏那个文件。
如果一个方法调用了其自身的话,我们称之为递归调用。假定栈空间足够的话,尽管递归调用比较难以调试,在Java语言中实现递归调用也是完全可行的。递归方法是众多算法中替代循环的一个不错选择。所有的递归方法都是可重入的,但是不是所有可重入的方法都是递归的。
栈遵守LIFO(Last In First Out)规则,因此递归调用方法能够记住“调用者”并且知道此轮执行结束之返回至当初的被调用位置。递归利用系统栈来存储方法调用的返回地址。 Java是一种基于栈设计的编程语言。
顺着这个思路还有那些问题可以用来面试?
Q.什么情况下应该采用递归?
A. 上面的例子中其实不必采用递归,循环的方式可以达到目的,但是在某些情况下采用递归方式则代码会更加简短易读。递归方法在循环树结构以及避免丑陋的嵌套循环的情况下是非常好用的。
Q.什么是尾递归,为什么需要尾递归?上面的代码用尾递归方式如何重写?
A. 常规递归方法(亦称,头递归)在上面演示了,这种方式会增加调用栈的大小。每次递归,其入口需要被记录在栈中。方法返回之前需要给countA(input.substring(1)的结果加一个count。假定count大于1,那么返回结果就是count + countA(input.substring(1)),当然事先要算出来countA(input.substring(1))才行。同时,这也意味着直到countA(input.substring(1)计算出来才能得到最终的结果。因此,最后需要做的事其实是加法运算,而非递归本身。
尾递归的好处是什么?
在尾递归中,最后要做的是递归,加法运算在之前就已经完成了。一轮递归调用完毕后就没有其他事情了(除了加法运算),因此调用时生成的信息也就没什么用了。这些无用信息可以丢弃,然后用一组新的参数来调用一次递归方法来产生一个新的结果。这也就是说,栈调用减少带来了内存消耗减少并且程序的性能更好。
尾递归重写的代码如下:
public class TailRecursiveCall { public int countA(String input) { // exit condition – recursive calls must have an exit condition if (input == null || input.length() == 0) { return 0; } return countA(input, 0) ; } public int countA(String input, int count) { if (input.length() == 0) { return count; } // check first character of the input if (input.substring(0, 1).equals("A")) { count = count + 1; } // recursive call is the last call as the count is cumulative return countA(input.substring(1), count); } public static void main(String[] args) { System.out.println(new TailRecursiveCall().countA("AAA rating")); } }
相关推荐
本话题将聚焦于幂函数的计算,比较两种常见方法:迭代(Iteration)与递归(Recursion)。我们将深入探讨这两种方法在Java语言中的实现,并分析它们的时间复杂度和实际运行效率。 幂函数是数学中的一种基本运算,...
根据给定文件的信息,我们可以深入探讨递归与迭代这两个重要的编程概念。递归与迭代都是解决计算机科学领域问题的重要方法,它们在算法设计、数据结构处理等方面有着广泛的应用。 ### 一、递归 #### 1.1 什么是...
### BAT各大互联网面试题知识点详解 #### 一、设置DOM元素CSS样式的三种方式 1. **外部样式表**:通过`<link>`标签引入一个外部的CSS文件,这种方式适用于多个页面共享相同的样式规则,有利于代码复用和维护。 ``...
首先,“算法和数据结构——迭代和递推(上)”这个标题提示了文档将讨论算法领域中非常核心的两个概念:迭代(Iteration)和递归(Recursion)。这两者在计算机科学中用于实现程序的重复操作和问题求解的基本方法。...
策略迭代(Policy Iteration)是强化学习中的一种经典算法,适用于离散状态和动作空间的问题。本篇文章将深入探讨如何在Python中实现策略迭代算法。 策略迭代算法主要包括两个步骤:策略评估(Policy Evaluation)...
为了避免这种情况,可以考虑使用尾递归(Tail Recursion)、记忆化(Memoization)或迭代(Iteration)等优化方法。 尾递归是指在递归调用的最后返回结果,这样编译器或解释器有可能优化掉多余的栈帧,减少内存消耗...
递归与循环是C语言中实现迭代逻辑的两种强大工具,它们各有优势和适用场景。递归提供了一种简洁的方式来解决分而治之的问题,但在使用时需要注意避免栈溢出和重复计算的问题。循环则是一种更为直接且通常更高效的...
- **Recursion vs Iteration**:面试中可能会考察如何使用递归和迭代解决问题。 4. **VoIP技术**: - **H.323**:一种广泛使用的IP电话协议,涉及终端(EP)、网关控制(GK)、计费系统等组件。 - **SIP...
在这个主题中,我们将深入探讨基于Python的值迭代算法(Value Iteration)实现,这是一种解决有限马尔科夫决策过程(Finite Markov Decision Process, MDP)的经典方法。 值迭代算法是强化学习的基础算法之一,它...
在数值分析领域,迭代方法是求解线性方程组的一种常见策略,特别是当系统规模较大,直接解法(如高斯消元法)变得不切实际时。本主题涉及三种迭代方法:雅克比迭代、高斯迭代以及松弛法(SOR)迭代,并提供了相应的...
在编程领域,迭代是一种反复执行某个过程直到满足特定条件的操作,通常用于遍历数组或对象。在JavaScript中,迭代有着多种实现方式,这些方法都为我们提供了处理数据的强大工具。本篇将深入探讨“迭代作为代码抽象的...
数值迭代算法是解决数学方程组或非线性问题的一种常用方法,特别是在计算机科学和工程领域。这种方法通过一系列近似步骤逐步逼近问题的精确解。在本教程中,我们将深入探讨数值迭代的基本概念,以及如何在强大的编程...
在数值计算领域,牛顿迭代法、对分法、雅可比迭代和高斯赛德尔迭代是四种常用且重要的算法,它们主要用于解决不同类型的数学问题。以下是对这些方法的详细阐述: 1. 牛顿迭代法(Newton's Iteration Method): ...
本文将重点讨论两种常用的迭代法——雅可比迭代法(Jacobi Iteration)和高斯-赛德尔迭代法(Gauss-Seidel Iteration),以及如何用C语言实现它们。 雅可比迭代法是基于分块对角线主导的线性方程组的一种迭代策略。...
在数值分析领域,迭代法是一种求解线性方程组的有效方法。在MATLAB中,我们可以利用编程实现这些算法,以便于理解和应用。本主题主要关注三种迭代法:雅可比迭代、高斯-赛德尔迭代以及松弛法迭代,并探讨它们的收敛...
作为Java语言的爱好者,在找工作的时候遇到了许多Java多线程的面试题,既是对多线程的学习,也是对其的理解。
最小二乘策略迭代(Least Squares Policy Iteration, LSPI)是一种强化学习算法,它结合了策略迭代(Policy Iteration)的基本思想与数值优化方法,特别是最小二乘法,用于解决连续状态空间和动作空间的问题。...
本资源是一个关于MDP的实践项目,重点在于策略迭代(Policy Iteration)算法的实现,使用了MATLAB编程语言。 策略迭代是MDP求解的核心算法之一,它包括两个主要步骤:策略评估(Policy Evaluation)和策略改进...
在数值分析领域,雅可比迭代(Jacobi Iteration)和高斯-塞德尔迭代(Gauss-Seidel Iteration)是两种广泛用于求解大型线性方程组的方法。这两种迭代法都基于矩阵分解和迭代更新的思想,适用于处理稀疏矩阵问题,...