那天闲来无聊,突然从网上看到一google面试题,比较有意思,于是整理了下先写下来,算法大概是这样的:
T(0) = T(1) = 1;
T(2) = 2;
T(N) = T(N-1) + T(N-2) + T(N-3);
算法前提不考虑溢出,于是我写下了最常规的递归算法:
public class Tribonacci {
public static int method(int n) {
if( 0 == n || 1 == n) {
return 1;
} else if( 2 == n) {
return 2;
} else {
return method(n - 1) + method(n - 2) + method(n - 3);
}
}
}
但是仔细琢磨了下,当n >= 3 事, 条件进入最后的else,这里其实进行了多次递归,其中 在递归n-1的时候其实已经计算出了n-2、n-3, 所以这个算发,很显然重复计算了后便的method(n-2)、method(n-3),所以这里可以在计算method(n-1)的时候记住n-2、与n-3的值,百般思索后写出了如下的程序:
public class Tribonacci {
public static int method2(int n) {
if( n < 0) {
return 0;
}
if( 0 == n || 1 == n ) {
return 1;
}
if( 2 == n ) {
return 2;
}
ReferenceInt mid = new ReferenceInt();
ReferenceInt last = new ReferenceInt();
int max_subset = sub_recursion( n, mid, last);
return max_subset + mid.getValue() + last.getValue();
}
public static int sub_recursion(int n, ReferenceInt mid, ReferenceInt last) {
if ( 3 == n ) {
mid.setValue(1);
last.setValue(1);
return 2;
} else {
ReferenceInt temp = new ReferenceInt();
//这里做了参数移位,原来的last变为n-1的mid, 启用新的变量带出n-1的last
mid.setValue(sub_recursion( n - 1, last, temp));
return mid.getValue() + last.getValue() + temp.getValue();
}
}
/**
* 由于Java讨厌的自动封包机制,这里自己定义一个int的包装类型
*/
class ReferenceInt {
private int value;
public ReferenceInt(int value) {
this.value = value;
}
public ReferenceInt() {
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String toString() {
return String.valueOf(this.value);
}
}
}
算法的思想就是在计算n-1的时候,用参数带出n-2与n-3的值,去掉重复的计算,减少递归的次数,达到优化算法的效果,这里我简单说一下:
T(N) = T(N-1) + T(N-2) + T(N-3);
mas_sub mid last
话说一个哥们,用list来缓存n-2 -> 0 之间的结果,随说有点吃内存,不过看起来比上边这个算法,好看多了,呵呵,都说是G内存的时代了,我一听乐了,不过也算是懒人有懒办法吧,贴出来大家看下:
public class Tribonacci {
public static List<Integer> list = new ArrayList<Integer>();
static {
list.add(1);
list.add(1);
list.add(2);
}
public static int method3(int n) {
if(n<list.size()){
return list.get(n).intValue();
}else{
for(int i=list.size();i<=n;i++){
list.add(method3(i - 1) + method3(i - 2) + method3(i - 3));
}
return method3(n);
}
}
}
呵呵,下边测试一下3个算法的性能吧:
public class Tribonacci {
public static void main(String[] args) {
final int TEST_NUMBER = 35;
long start = System.currentTimeMillis();
System.out.print(Tribonacci.method1(TEST_NUMBER));
long end = System.currentTimeMillis();
System.out.println("->method1(" + TEST_NUMBER + ") cost:" + (end-start) + "ms");
start = System.currentTimeMillis();
System.out.print(Tribonacci.method2(TEST_NUMBER));
end = System.currentTimeMillis();
System.out.println("->method2(" + TEST_NUMBER + ") cost:" + (end-start) + "ms");
start = System.currentTimeMillis();
System.out.print(Tribonacci.method3(TEST_NUMBER));
end = System.currentTimeMillis();
System.out.println("->method3(" + TEST_NUMBER + ") cost:" + (end-start) + "ms");
}
}
1132436852->method1(35) cost:10468ms
1132436852->method2(35) cost:0ms
1132436852->method3(35) cost:0ms
分享到:
相关推荐
本篇文章将深入探讨.NET中如何进行递归算法的优化,以及提供相关的源码案例。 一、理解递归 递归算法的基本思想是函数在执行过程中调用自身,每次调用都会创建一个新的函数调用栈帧。递归通常包含两个关键部分:...
在.NET编程环境中,递归算法是一种强大的工具,它允许函数或方法调用自身来解决复杂问题。递归的核心思想是将大问题分解为相同或相似的小问题,直到问题变得足够简单,可以直接得出答案。这种解决问题的方式在数据...
7. **动态规划与记忆化**:为了优化递归算法,可以采用动态规划的思想,将已经计算过的子问题结果存储起来,避免重复计算,这种方法称为记忆化搜索。 8. **递归与分治策略**:递归往往是分治算法的实现方式,如快速...
3. **可读性和实现难度**:递归算法通常代码简洁,易于理解,而非递归算法可能需要更复杂的逻辑来模拟递归行为。 总的来说,选择哪种实现方式取决于具体场景,如内存限制、性能要求以及代码的可读性等。递归版本的...
### 递归算法在程序设计中的应用 #### 一、递归的概念与本质 递归是一种重要的编程思想,在计算机科学和数学领域都有广泛的应用。它指的是一个过程或函数直接或间接地调用自身来解决问题的方法。递归的核心在于将...
### 递归算法专题知识点详解 #### 一、递归算法原理 递归算法是一种将问题分解成子问题的方法,其中子问题与原问题性质相同但规模较小。递归算法的关键在于识别出能够通过递归解决的问题,并找到递归的基本情况...
在IT领域,尤其是在数据结构与算法的学习中,中序遍历二叉树的非递归算法是一个关键且实用的知识点。通常,我们首先通过递归来实现二叉树的遍历,但递归方法可能因深度过大导致栈溢出,因此掌握非递归版本的遍历算法...
然而,在某些场景下,非递归算法可能更有利于性能优化或理解。本章将探讨如何将递归算法转换为非递归算法。 首先,我们要了解递归的定义。递归发生在一个过程或函数在定义中调用自身,这被称为直接递归。如果一个...
**背包问题递归算法在C语言中的实现** 背包问题是一个经典的计算机科学问题,它涉及到在给定容量限制的背包中,如何选择物品以达到最大的价值。这个问题通常被用来模拟资源有限的情况下的决策优化,比如投资组合...
3. **尾递归优化**:在某些语言中,如Scala或Haskell,可以利用尾递归特性来优化递归算法,使得其运行效率接近于循环。 4. **数学公式**:对于斐波那契数列,存在闭合形式的解,即著名的Binet公式,虽然在实际编程...
关于递归算法时间复杂度分析的探讨,是一个深入理解算法效率和优化的关键议题。递归,作为解决问题的一种强大工具,其本质是将复杂问题分解为更简单的子问题,通过求解这些子问题来达到最终解决方案的目的。然而,...
在这个压缩包中,你将找到两个关于阿克曼函数的C语言实现:一个使用了递归算法,另一个则通过栈来模拟递归。 首先,让我们深入理解阿克曼函数。它通常定义为A(m, n),其中m和n是正整数。阿克曼函数的计算规则如下:...
在编程领域,递归算法是一种基于函数自我调用的解决问题的方法。它通常用于解决那些可以被简化为相同问题子集的问题。"易语言"是中国的一种简单易学的编程语言,旨在降低编程难度,让更多人能接触编程。在这个场景中...
### Python基于递归算法实现的走迷宫问题详解 #### 一、递归算法简介 在探讨如何使用Python实现走迷宫问题...同时,也需要注意递归算法可能带来的性能问题,适时采取优化措施,如尾递归优化或者使用迭代方法替代。
然而,递归算法也有其局限性,如过度的递归调用可能导致栈溢出等问题,因此在实际应用中需注意控制递归深度和优化算法效率。 总之,理解递归算法以及如何在具体问题中运用它,是程序员和算法设计师必备的技能之一。...
### Hanoi塔问题非递归算法的形式推导 #### 一、引言 Hanoi塔问题,也称为汉诺塔问题,是一个...这种非递归算法不仅适用于Hanoi塔问题,其思想还可以应用于其他类似的递归问题,为优化递归算法提供了一个新的视角。
### 递归算法计算斐波那契数列 #### 知识点概览 1. **斐波那契数列定义** 2. **递归算法原理** 3. **递归函数设计** 4. **递归算法的时间复杂度分析** 5. **C语言实现递归斐波那契数列** #### 斐波那契数列定义 ...
在编程领域,递归算法是一种强大的工具,尤其在处理具有层次结构的问题时。在C#中,递归常被用于解决复杂的数据结构问题,如树形结构的遍历。本篇我们将深入探讨“C#递归算法经典示例”,特别关注如何使用递归算法...
### 二叉树遍历的非递归算法分析与实现 #### 一、引言 在数据结构领域中,二叉树作为一种基本的数据组织形式,其应用极为广泛。对于二叉树的操作,其中最重要的就是遍历操作。遍历是指按照特定顺序访问二叉树的...
实验的结论部分可能总结了非递归算法的效率和适用性,并可能讨论了进一步的优化或改进方向,比如如何更有效地实现盘子的移动,或者如何扩展算法以适应更大的盘子数量。 附带的源代码中定义了一个结构体`dish`来存储...