概述
简介
程序调用自身的编程技巧称为递归,递归解决问题通常名为暴力搜索
三要素
明确递归终止条件
给出递归终止时的处理办法
可以提取重复逻辑,缩小问题规模
优点
递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量
缺点
递归解决问题运行效率较低,因此应该尽量避免使用递归
在递归调用的过程中系统为每一层的返回点 ,局部量等开辟了栈来储存,递归次数过多可能会造成栈溢出。
解决递归问题的思路
没思路时
1.画树
2.找出口
递归的两套模板
/**
* 打印1-100
*/
public class Main {
public static void main(String[] args) {
f1(1);
System.out.println();
f2(100);
}
/**
* 递的时候打印
*
* @param n
*/
public static void f1(int n) {
if (n <= 100) {
System.out.print(n + " ");
f1(n + 1);
}
}
/**
* 归的时候打印
*
* @param n
*/
public static void f2(int n) {
if (n >= 1) {
f2(n - 1);
System.out.print(n + " ");
}
}
}
简单算法
求斐波那契数列的第n项
问题
求斐波那契数列的第n项
波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55【每个数字是前两个数字的和】
实现
/**
* 求斐波那契数列的第n项
*
* 波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55【每个数字是前两个数字的和】
*/
public class Main {
public static void main(String[] args) {
System.out.println(fibonacci(5));
}
public static int fibonacci(int n) {
if (n > 1) {
return fibonacci(n - 1) + fibonacci(n - 2);
} else {
return n;
}
}
}
爬楼梯问题
问题
一个楼梯总共有n级台阶,你每次可以走1个台阶或者两个台阶,问从第0级台阶走到第n级台阶一共有多少种方案
思路
1.此算法类型为深度优先搜索
2.可以画树
实现
/**
* 爬楼梯问题
*
* 问题: 一个楼梯总共有n级台阶,问从第0级台阶走到第n级台阶一共有多少种方案。
* 你每次可以走1个台阶或者两个台阶。
*/
public class Main {
private static int res = 0;
public static void main(String[] args) {
f1(0, 4);
System.out.println(res);
}
/**
*
* @param startFloor 开始台阶
* @param endFloor 结束台阶
*/
private static void f1(int startFloor, int endFloor) {
//如果爬上了最后一层台阶,说明找到了一种方案
if (startFloor == endFloor) {
res++;
}
//如果没有爬完,则可能爬1或者2阶台阶
if (startFloor < endFloor) {
f1(startFloor + 1, endFloor);
f1(startFloor + 2, endFloor);
}
}
}
中等算法
全排列
来源
. - 力扣(LeetCode)
题目
给定一个不含重复数字的整数数组 nums ,返回其所有可能的全排列 ,可以按任意顺序返回答案
思路
实现
import java.util.ArrayList;
import java.util.List;
class Solution {
//全排列集合
List> itemList = new ArrayList();
//存放每一个方案的数组
List item = new ArrayList();
//用于判断当前数字有没有被用过的数组
boolean[] haveUse;
public List> permute(int[] nums) {
haveUse = new boolean[nums.length];
f(0, nums);
return itemList;
}
void f(int start, int[] nums) {
//如果所有数都被用过了,说明找到了一组方案
if (start == nums.length) {
itemList.add(new ArrayList(item));
}
//否则就循环遍历数组
for (int i = 0; i < nums.length; i++) {
if (!haveUse[i]) {
item.add(nums[i]);
haveUse[i] = true;//加入方案数组后,标记该数字被使用
f(start + 1, nums);
// 回溯
haveUse[i] = false;
item.remove(item.size() - 1);
}
}
}
}