程序员的算法课(3)-递归(recursion)算法
一、什么是递归
递归是一种数学上分而自治的思想。
- 递归将大型复杂问题转化为与原问题相同但规模较小
- 的问题进行处理
- 递归需要有边界条件,当边界条件不满足时,递归继续进行;当边界条件满足时,递归停止
【百度百科】程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
二、递归的数学表示

三、一些数学问题的递归解法
1.斐波那契数列
经典数学问题之一;斐波那契数列,又称黄金分割数列,指的是这样一个数列: 1、1、2、3、5、8、13、21、……
这个数列的规律,就是前两项的和是第三项的值,
public class Solution {
public int Fibonacci(int n) {
if(n == 0)
return 0;
if(n == 1)
return 1;
return Fibonacci(n-2) + Fibonacci(n-1);
}
}
当n比较大时,可以明显感觉算法运行速度比较慢,这是由于上述返回代码中使用了两层递归,使用递归的思想是好的,但是这里我们可以用迭代明显改善算法运行效率,用空间换时间。
public class Solution {
public int Fibonacci(int n) {
if(n < 2)
return n;
int f = 0, g = 1;
int result = 0;
for(int i = 1; i < n; i++){
result = f + g;
f = g;
g = result;
}
return result;
}
}
2.汉诺塔
汉诺塔是一个发源于印度的益智游戏,也叫河内塔。相传它源于印度神话中的大梵天创造的三个金刚柱,一根柱子上叠着上下从小到大64个黄金圆盘。大梵天命令婆罗门将这些圆盘按从小到大的顺序移动到另一根柱子上,其中大圆盘不能放在小圆盘上面。当这64个圆盘移动完的时候,世界就将毁灭。

public class Hanoilmpl {
public void hanoi(int n, char A, char B, char C) {
if (n == 1) {
move(A, C);
} else {
hanoi(n - 1, A, C, B);//步骤1 按ACB数序执行N-1的汉诺塔移动
move(A, C); //步骤2 执行最大盘子移动
hanoi(n - 1, B, A, C);//步骤3 按BAC数序执行N-1的汉诺塔移动
}
}
private void move(char A, char C) {//执行最大盘子的从A-C的移动
System.out.println("move:" + A + "--->" + C);
}
public static void main(String[] args) {
Hanoilmpl hanoi = new Hanoilmpl();
System.out.println("移动汉诺塔的步骤:");
hanoi.hanoi(3, 'a', 'b', 'c');
}
}
3.八皇后问题
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。
在一个8°¡8国际象棋盘上,有8个皇后,每个皇后占一格;要求皇后间不会出现相互“攻击”的现象,即不能有两个皇后处在同一行、同一列或同一对角线上。

算法思路
- 初始化:i = 1
- 初始化:j = 1
- 从第i行开始,恢复j的当前值,判断第j个位置
a. 位置j可放入皇后:标记位置(i, j), i++,转步骤2
b. 位置j不可放入皇后:j++, 转步骤a
c. 当j>8时,i--,转步骤3
4.结束:第8行有位置可放入皇后
注意事项:当使用递归的时候,我们需要在执行后将map[row][i] 重新设置为0 ,保证下一次排列的时候棋盘是空的
/**
* 递归算法之八皇后问题
*
* @author Administrator
*/
public class Bahuanghou {
//定义一个8*8的矩阵
public static int[][] map = new int[8][8];
public static int count = 1; /**
* 显示棋盘方法
*/
public static void show() {
System.out.println("第" + count + "中排列方式");
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}
count++;
} /**
* 检验方法(验证该位置是否可以放皇后)
*/
public static boolean check(int row, int col) {
//上面(行减小 列不变)
for (int i = row - 1; i >= 0; i--) {
if (map[i][col] == 1) {
return false;
}
} //左斜上 (行减小 列减小)
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { if (map[i][j] == 1) {
return false;
} }
//右斜上 (行减小 列增加)
for (int i = row - 1, j = col + 1; i >= 0 && j < 8; i--, j++) { if (map[i][j] == 1) {
return false;
} }
return true;
} /**
* 八皇后算法
*/
public static void play(int row) { //遍历当前行的所有单元格
for (int i = 0; i < 8; i++) {
//判断本格是否可以放皇后
if (check(row, i)) {
map[row][i] = 1;
//判断是否为最后一行
if (row == 7) {
show();
} else {
//接着走下一行
play(row + 1);
} //取消当前落子 清空棋盘
map[row][i] = 0;
}
}
} public static void main(String[] args) {
play(0);
}
}
四、总结
对于递归思想可以有如下总结:
- 采用递归编程最好持有“井底之蛙”的思想;
- 递归的特点在于:它一次只打算解决一点点的问题。
对于递归实现可以关注两点:
- 递归的出口条件;
- 归纳法中得到的规律。
我的微信公众号:架构真经(id:gentoo666),分享Java干货,高并发编程,热门技术教程,微服务及分布式技术,架构设计,区块链技术,人工智能,大数据,Java面试题,以及前沿热门资讯等。每日更新哦!

参考资料:
程序员的算法课(3)-递归(recursion)算法的更多相关文章
- Java常用排序算法+程序员必须掌握的8大排序算法+二分法查找法
Java 常用排序算法/程序员必须掌握的 8大排序算法 本文由网络资料整理转载而来,如有问题,欢迎指正! 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排 ...
- Java 常用排序算法/程序员必须掌握的 8大排序算法
Java 常用排序算法/程序员必须掌握的 8大排序算法 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配 ...
- 写给嵌入式程序员的循环冗余校验(CRC)算法入门引导
写给嵌入式程序员的循环冗余校验(CRC)算法入门引导 http://blog.csdn.net/liyuanbhu/article/details/7882789 前言 CRC校验(循环冗余校验)是数 ...
- 《PHP程序员面试笔试宝典》——如何回答算法设计问题?
如何巧妙地回答面试官的问题? 本文摘自<PHP程序员面试笔试宝典> 程序员面试中的很多算法设计问题,都是历年来各家企业的"炒现饭",不管求职者以前对算法知识掌握得是否扎 ...
- Java常用排序算法+程序员必须掌握的8大排序算法
概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们这里说说八大排序就是内部排序. 当n较大, ...
- java程序员到底该不该了解一点算法(一个简单的递归计算斐波那契数列的案例说明算法对程序的重要性)
为什么说 “算法是程序的灵魂这句话一点也不为过”,递归计算斐波那契数列的第50项是多少? 方案一:只是单纯的使用递归,递归的那个方法被执行了250多亿次,耗时1分钟还要多. 方案二:用一个map去存储 ...
- Java程序员必须掌握的8大排序算法
分类: 1)插入排序(直接插入排序.希尔排序)2)交换排序(冒泡排序.快速排序)3)选择排序(直接选择排序.堆排序)4)归并排序5)分配排序(基数排序) 所需辅助空间最多:归并排序所需辅助空间最少:堆 ...
- [转]Java 常用排序算法/程序员必须掌握的 8大排序算法
本文转自:http://www.cnblogs.com/qqzy168/archive/2013/08/03/3219201.html 本文由网络资料整理转载而来,如有问题,欢迎指正! 分类: 1)插 ...
- Java程序员必知的8大排序算法
8种排序之间的关系 直接插入排序 (1)基本思想:在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排 好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数 也是排好顺序的.如 ...
- 程序员代码面试指南:IT名企算法与数据结构题目最优解
第1章栈和队列 1设计一个有getMin功能的栈(士★☆☆☆) 1由两个栈组成的队列(尉★★☆☆) 5如何仅用递归函数和栈操作逆序一个栈(尉★★☆☆) 8猫狗队列(士★☆☆☆)10用一个栈实现另一 ...
随机推荐
- [2018-01-13] 什么是Django
什么是Django? Django是一个基于Python的高级Web开发框架 它能够让开发人员进行高效且快速的开发 高度集成(不用自己造轮子),免费并且开源(内部已经实现了许多高级的功能) 浏览器浏览 ...
- 题解 【洛谷】AT654
题解 AT654 [役人[错题已隐藏]] 此题题面没搬过来, 会日语的dalao可以自行去ATCoder查看. 给出此题的JavaAC代码: public class Main { public st ...
- Java迭代Map方法
Map map=new HashMap(); map.put("1", "one"); map.put("2","two" ...
- IDEA复制多行及对多行代码上下左右移动
复制: 复制一行可不需要选中 多行需要选中 mac:command+D window:ctrl+D 移动: 选中代码 左移:tab+shift 右移:tab 上移:shift+alt+向上方向键 下移 ...
- Lost My Music:倍增实现可持久化单调栈维护凸包
题目就是求树上每个节点的所有祖先中(ci-cj)/(dj-di)的最小值. 那么就是(ci-cj)/(di-dj)的最大值了. 对于每一个点,它的(ci,di)都是二维坐标系里的一个点 要求的就是祖先 ...
- NOIP模拟 9
%liu_runda Orz T1 随 矩阵快速幂结合概率期望 但n3无法承受 利用原根的性质,将乘法转化成加法 就变成循环矩阵n^2了 改题时苦b地卡了关:误把1当成原根的1次方,错误地认为矩阵的阶 ...
- ES入门宝典(详细截图版)
本文使用版本基于elasticsearch-6.4.0 1.什么是ES? 官网: https://www.elastic.co/products/elasticsearch 中文官网:https:/ ...
- 树上神奇 逆 逆序对(我的叫法)hh的小纸条 重中之重!!!!!
HH是一位十分爱好数学的大佬,尤其喜爱数数,一天百无聊赖的他写下了一个1-N的排列,并且在小纸条上记下了每个数前面有多少个数比他小,但HH不小心忘记了这个排列.现在只有当时记下的小纸条,现在请你还原出 ...
- postman-接口间数据传递
接口间数据传递 在我们做接口测试过程中会经常碰到使用上一个接口返回数据的情况,jmeter中可通过正则表达式提取,postman中如何提取呢?我们来看实例,这里使用的同一个接口来演示. 我们提取出 ...
- [转载]2.2 UiPath条件判断活动Flow Decision的介绍和使用
一.Flow Decision介绍 FlowDecision节点是一个条件节点,它根据指定条件是否成立来控制流程的两个分支. 当条件为True时,流程执行一个分支 当条件为False时,流程执行另外一 ...