几个简单递归问题(菲波那契数列 ,二叉树,逆波兰式)
2013-04-29 15:12
411 查看
9.2 例题:菲波那契数列
问题描述
菲波那契数列是指这样的数列:数列的第一个和第二个数都为 1,接下来每个数都等于前面 2 个数之和。给出一个正整数 a,要求菲波那契数列中第 a 个数是多少。
输入数据
第 1 行是测试数据的组数 n,后面跟着 n 行输入。每组测试数据占 1 行,包括一个
正整数 a(1 <= a <= 20)。
输出要求
n 行,每行输出对应一个输入。输出应是一个正整数,为菲波那契数列中第 a 个数
的大小。
输入样例
4
5
2
19
1
输出样例
5
1
4181
1
解题思路:这个题目要求很明确,因为 a的规模很小,所以递归调用不会产生栈溢
出的问题。设第 n 项值为 f(n),则 f(n) = f(n-1)+f(n-2)。已知 f(1)=1,f(2)=1,则从第3
项开始,可以用公式求。
import java.util.Scanner;
/*斐波那契数列
* 1 1 2 3 5 8 13.....
* */
public class Test9_2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
System.out.println(f(n));
}
public static int f(int n)
{
if(n==1||n==2)
return 1;
return f(n-1)+f(n-2);
}
}
思考题9.2:在n比较大(比如,n>10)的时候,函数f的执行次数和下面哪一项比
较接近?
A) n^2 B) n^3 C) 2^n D) n!
9.3 例题:二叉树
问题描述
如上图所示,由正整数 1, 2, 3, ...组成了一棵无限大的二叉树。从某一个结点到根结点(编号是 1 的结点)都有一条唯一的路径,比如从 10 到根结点的路径是(10, 5, 2, 1),
从 4 到根结点的路径是(4, 2, 1),从根结点 1 到根结点的路径上只包含一个结点 1,因此路径就是(1)。对于两个结点 x 和 y,假设他们到根结点的路径分别是(x1, x2, ... ,1)和(y1,
y2, ... ,1)(这里显然有 x = x1,y = y1),那么必然存在两个正整数 i 和 j,使得从 xi 和 yj开始,有 xi = yj ,xi + 1 = yj + 1,xi + 2 = yj + 2,... 现在的问题就是,给定 x 和y,要求 xi(也就是 yj)。
输入数据
输入只有一行,包括两个正整数 x 和 y,这两个正整数都不大于 1000。
输出要求
输出只有一个正整数 xi。
输入样例
10 4
输出样例
2
解题思路
这个题目要求树上任意两个节点的最近公共子节点。分析这棵树的结构不难看出,不论奇数偶数,每个数对 2 做整数除法,就走到它的上层结点。 我们可以每次让较大的一个数(也就是在树上位于较低层次的节点)向上走一个结点,直到两个结点相遇。如果两个节点位于同一层,并且它们不相等,可以让其中任何一个先往上走,然后另一个再往上走,直到它们相遇。设 common(x, y)表示整数 x 和 y的最近公共子节点,那么,根据比较 x 和y 的值,我们得到三种情况:1) x 与y 相等,则 common(x, y)等于 x 并且等于y;2)x
大于 y,则 common(x, y)等于 common(x/2, y);3)x 大于 y,则 common(x, y)等于 common(x y/2);
import java.util.Scanner;
//二叉树,求另个结点到根节点的路径中重复的位置
public class Test9_3 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int x=sc.nextInt();
int y=sc.nextInt();
System.out.println(f(x,y));
}
public static int f(int x,int y)
{
if(x==y)
return x;
else if(x>y)
return f(x/2,y);
else
return f(x,y/2);
}
}
实现中常见的问题
问题一:有一种比较直观的解法是对于两个给定的数,分别求出它们到根节点的通路上的所有节点的值,然后再在两个数组中寻找数码最大的公共节点。这种做法的代码
比较繁琐,容易在实现中出错;
问题二:代码实现逻辑不明晰,造成死循环等错误,例如,有人只将其中一个数不停地除以 2,而不理会另外一个数。
9.4 例题:逆波兰表达式
问题描述
逆波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式 2 + 3 的逆波兰表示法为+ 2 3。逆波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4 的逆波兰表示法为* + 2 3 4。本题求解逆波兰表达式的值,其中运算符包括 + - * / 四个。
输入数据
输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数
输出要求
输出为一行,表达式的值。
输入样例
* + 11.0 12.0 + 24.0 35.0
输出样例
1357.000000
解题思路
这个问题看上去有些复杂,如果只是简单地模拟计算步骤不太容易想清楚,但是如果用递归的思想就非常容易想清楚。让我们根据逆波兰表达式的定义进行递归求解。在递归函数中,针对当前的输入,有五种情况:1)输入是常数,则表达式的值就是这个常数;2)输入是’+’,则表达式的值是再继续读入两个表达式并计算出它们的值,然后将它们的值相加;3)输入是’-’;4)输入是’*’; 5)输入是’/’;后几种情况与 2)相同,只是计算从’+’变成’-’,’*’,’/’。
import java.util.Scanner;
//给一个用逆波兰式表示的数学式子,求出结果
public class Test9_4 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(cal());
}
public static float cal()
{
Scanner sc=new Scanner(System.in);
String c=sc.nextLine();//每当输入一个字符后要按回车键
//System.out.println(c);
if(c.equals("+"))
//System.out.print("("+cal()+"+"+cal()+")")将逆波兰式转化成常规表达式输出
return cal()+cal();
if(c.equals("-"))
return cal()-cal();
if(c.equals("*"))
return cal()*cal();
if(c.equals("/"))
return cal()/cal();
return Float.parseFloat(c);
}
}
实现中常见的问题
问题一:不适应递归的思路,直接分析输入的字符串,试图自己写进栈出栈的程序,写得逻辑复杂后,因考虑不周出错;
问题二:不会是用 atof()函数,自己处理浮点数的读入,逻辑复杂后出错。
思考题9.4:改写此程序,要求将逆波兰表达式转换成常规表达式输出。可以包含多余的括号。
问题描述
菲波那契数列是指这样的数列:数列的第一个和第二个数都为 1,接下来每个数都等于前面 2 个数之和。给出一个正整数 a,要求菲波那契数列中第 a 个数是多少。
输入数据
第 1 行是测试数据的组数 n,后面跟着 n 行输入。每组测试数据占 1 行,包括一个
正整数 a(1 <= a <= 20)。
输出要求
n 行,每行输出对应一个输入。输出应是一个正整数,为菲波那契数列中第 a 个数
的大小。
输入样例
4
5
2
19
1
输出样例
5
1
4181
1
解题思路:这个题目要求很明确,因为 a的规模很小,所以递归调用不会产生栈溢
出的问题。设第 n 项值为 f(n),则 f(n) = f(n-1)+f(n-2)。已知 f(1)=1,f(2)=1,则从第3
项开始,可以用公式求。
import java.util.Scanner;
/*斐波那契数列
* 1 1 2 3 5 8 13.....
* */
public class Test9_2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
System.out.println(f(n));
}
public static int f(int n)
{
if(n==1||n==2)
return 1;
return f(n-1)+f(n-2);
}
}
思考题9.2:在n比较大(比如,n>10)的时候,函数f的执行次数和下面哪一项比
较接近?
A) n^2 B) n^3 C) 2^n D) n!
9.3 例题:二叉树
问题描述
如上图所示,由正整数 1, 2, 3, ...组成了一棵无限大的二叉树。从某一个结点到根结点(编号是 1 的结点)都有一条唯一的路径,比如从 10 到根结点的路径是(10, 5, 2, 1),
从 4 到根结点的路径是(4, 2, 1),从根结点 1 到根结点的路径上只包含一个结点 1,因此路径就是(1)。对于两个结点 x 和 y,假设他们到根结点的路径分别是(x1, x2, ... ,1)和(y1,
y2, ... ,1)(这里显然有 x = x1,y = y1),那么必然存在两个正整数 i 和 j,使得从 xi 和 yj开始,有 xi = yj ,xi + 1 = yj + 1,xi + 2 = yj + 2,... 现在的问题就是,给定 x 和y,要求 xi(也就是 yj)。
输入数据
输入只有一行,包括两个正整数 x 和 y,这两个正整数都不大于 1000。
输出要求
输出只有一个正整数 xi。
输入样例
10 4
输出样例
2
解题思路
这个题目要求树上任意两个节点的最近公共子节点。分析这棵树的结构不难看出,不论奇数偶数,每个数对 2 做整数除法,就走到它的上层结点。 我们可以每次让较大的一个数(也就是在树上位于较低层次的节点)向上走一个结点,直到两个结点相遇。如果两个节点位于同一层,并且它们不相等,可以让其中任何一个先往上走,然后另一个再往上走,直到它们相遇。设 common(x, y)表示整数 x 和 y的最近公共子节点,那么,根据比较 x 和y 的值,我们得到三种情况:1) x 与y 相等,则 common(x, y)等于 x 并且等于y;2)x
大于 y,则 common(x, y)等于 common(x/2, y);3)x 大于 y,则 common(x, y)等于 common(x y/2);
import java.util.Scanner;
//二叉树,求另个结点到根节点的路径中重复的位置
public class Test9_3 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int x=sc.nextInt();
int y=sc.nextInt();
System.out.println(f(x,y));
}
public static int f(int x,int y)
{
if(x==y)
return x;
else if(x>y)
return f(x/2,y);
else
return f(x,y/2);
}
}
实现中常见的问题
问题一:有一种比较直观的解法是对于两个给定的数,分别求出它们到根节点的通路上的所有节点的值,然后再在两个数组中寻找数码最大的公共节点。这种做法的代码
比较繁琐,容易在实现中出错;
问题二:代码实现逻辑不明晰,造成死循环等错误,例如,有人只将其中一个数不停地除以 2,而不理会另外一个数。
9.4 例题:逆波兰表达式
问题描述
逆波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式 2 + 3 的逆波兰表示法为+ 2 3。逆波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4 的逆波兰表示法为* + 2 3 4。本题求解逆波兰表达式的值,其中运算符包括 + - * / 四个。
输入数据
输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数
输出要求
输出为一行,表达式的值。
输入样例
* + 11.0 12.0 + 24.0 35.0
输出样例
1357.000000
解题思路
这个问题看上去有些复杂,如果只是简单地模拟计算步骤不太容易想清楚,但是如果用递归的思想就非常容易想清楚。让我们根据逆波兰表达式的定义进行递归求解。在递归函数中,针对当前的输入,有五种情况:1)输入是常数,则表达式的值就是这个常数;2)输入是’+’,则表达式的值是再继续读入两个表达式并计算出它们的值,然后将它们的值相加;3)输入是’-’;4)输入是’*’; 5)输入是’/’;后几种情况与 2)相同,只是计算从’+’变成’-’,’*’,’/’。
import java.util.Scanner;
//给一个用逆波兰式表示的数学式子,求出结果
public class Test9_4 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(cal());
}
public static float cal()
{
Scanner sc=new Scanner(System.in);
String c=sc.nextLine();//每当输入一个字符后要按回车键
//System.out.println(c);
if(c.equals("+"))
//System.out.print("("+cal()+"+"+cal()+")")将逆波兰式转化成常规表达式输出
return cal()+cal();
if(c.equals("-"))
return cal()-cal();
if(c.equals("*"))
return cal()*cal();
if(c.equals("/"))
return cal()/cal();
return Float.parseFloat(c);
}
}
实现中常见的问题
问题一:不适应递归的思路,直接分析输入的字符串,试图自己写进栈出栈的程序,写得逻辑复杂后,因考虑不周出错;
问题二:不会是用 atof()函数,自己处理浮点数的读入,逻辑复杂后出错。
思考题9.4:改写此程序,要求将逆波兰表达式转换成常规表达式输出。可以包含多余的括号。
相关文章推荐
- 搭建简单FTP服务器以及过程中容易遇到的几个问题(一)
- [LeetCode系列] 二叉树最大深度求解问题(C++递归解法)
- 解题笔记(15)——几个栈和递归的问题
- 二叉树的创建、前序中序后序递归遍历与非递归遍历、层序遍历以及二叉树简单应用的C语言实现
- 二叉树的递归遍历(思路简单清晰)
- 简单二叉树的创建和输出(递归)
- 用分冶策略解决关于二叉树的几个问题
- C++单元测试一:并非看上去那么简单——几个很实际的问题
- 递归的几个简单题目
- 二叉树的递归遍历(思路简单清晰)
- 9-简单实例(二)小程序开发中应注意的几个问题
- 简单的Memory leak跟踪(四)参考代码、组织和几个问题的讨论
- JavaSE 最容易出错的几个简单的问题
- 递归6_简单的0/1背包问题 去除相同的数
- poj2250(简单的二叉树问题) Tree Recovery
- 递归的几个简单题目
- JavaSE 最easy出错的几个简单的问题
- 上周开发过程中几个简单问题的总结
- 蓝桥杯2n皇后问题(简单递归回溯)
- 【LeetCode】三道简单的递归问题