蓝桥杯---递归

要点:

  • 1、相似性:找到相同的部分,将问题一分为二,每一部分可以容易算出或转换成规模小于原问题的类似问题;
  • 2、确定递归出口。

案例一:从n个球中取m个(组合问题)

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;

public class Main {

//	组合问题:从n个球中取m个
//	方法:通过递归枚举
	public static void main(String[] args) {
		int n = 10, m = 3;
		int y = 0;
		y = f(n, m);
		System.out.println(y);
	}

	private static int f(int n, int m) {
		//出口
		if(m==0||n==m) return 1;
		//其中一个球取+该球不取
		return f(n-1,m-1)+f(n-1,m);
	}
}

案例二:字符串有多少种不同的排列方式(排列问题)

思想:把每个元素都与第一个元素交换(也就是说第一个位置确定为某个元素),剩下的部分进行全排列。

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;

public class Main {

//	排列问题
	public static void main(String[] args) {
		char[] data = "ABC".toCharArray();//转换成字符数组
		f(data,0);
	}

//	k:表示要交换的当前位置
	private static void f(char[] data,int k) {
		if(k==data.length) {
			for (int i = 0; i < data.length; i++) {
				System.out.print(data[i]+" ");
			}
			System.out.println();
		}
		
//		循环条件中蕴含了递归出口
		for(int i=k;i<data.length;i++) {
//			交换
			{char t=data[k];data[k]=data[i];data[i]=t;}
			f(data,k+1);
//			回溯(换回来,保持)
			{char t=data[k];data[k]=data[i];data[i]=t;}
		}
	}
}

案例三:求最大公共子序列长度

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;

public class Main {

//	求最大公共子序列长度
	public static void main(String[] args) {
		String a = "abcd";
		String b = "acdba";
		int y = f(a, b);
		System.out.println(y);
	}

	private static int f(String a, String b) {
//		出口
		if(a.length()==0||b.length()==0) return 0;
		
//		两个串的第一个字符相同
		if(a.charAt(0)==b.charAt(0)) {
			return 1+f(a.substring(1),b.substring(1));
		}
//		两个串的第一个字符不相同
		else {
			return Math.max(f(a.substring(1),b.substring(0)), f(a.substring(0),b.substring(1)));
		}
	}
}

案例四:字符出串反转

public class Main {

	// 字符出串反转
	public static void main(String[] args) {
		String a = "abcde";
		System.out.println(f(a));

	}

	private static String f(String a) {
		if(a.length()==1) return a.charAt(0)+"";
		return f(a.substring(1))+a.charAt(0);
	}
}

案例五:输出杨辉三家的第m行

规律:该元素的值为上方元素的值加上左上方元素的值,第一列和每行的最后一个元素为1。

public class Main {

	// 杨辉三角的第m行
	public static void main(String[] args) {
		int m=3;
//		从第0行开始,第i行有i+1个元素
		for (int i = 0; i <= m; i++) {
			System.out.print(f(m,i)+" ");
		}
	}

	private static int f(int m, int n) {
		if(n==0) return 1;//从第0列开始
		if(n==m) return 1;
		return f(m-1,n)+f(m-1,n-1);
	}
}

案例六:m个a,n个b,有多少种排列方式

解题思路:从第一个位置开始,该位置要么为a,要么为b,剩下的部分是与原问题类似,且规模更小。

public class Main {

	// m个a,n个b,有多少种排列方式
	public static void main(String[] args) {
		System.out.println(f(3,2));
	}

	private static int f(int m, int n) {
		if(m==0||n==0) return 1;
		return f(m-1,n)+f(m,n-1);
	}
}

案例七:整数划分问题

解题思路:依次把n到1作为第一个加数,剩下的问题是与原问题相同,且规模更小的问题

public class Main {

	// 整数划分问题
	public static void main(String[] args) {
		int []a=new int[1000];
		f(6,a,0);
	}

//	对n进行划分
//	a[]用于暂存加数,k当前存储位置
	private static void f(int n,int []a,int k) {
		if(n==0){
			for (int i = 0; i < k; i++) {
				System.out.print(a[i]+" ");
			}
			System.out.println();
			return;
		}
		
		for(int i=n;i>0;i--){
			if(k>0&&a[k-1]<i) continue;
			a[k]=i;
			f(n-i,a,k+1);
		}
	}
}

案例八:账目错误问题

问题描述:某财务部门结账时发现总金额不对头。很可能是从明细上漏掉了某1笔或几笔。如果已知明细账目清单,能通过编程找到漏掉的是哪1笔或几笔吗?

解题思路:该笔账目要么记录了,要么没被记录,剩下的问题与原问题相似,且问题的规模更小。

public class Main {

//	 账目错误
/*	
 * 	问题描述:某财务部门结账时发现总金额不对头。
	很可能是从明细上漏掉了某1笔或几笔。如果已知
	明细账目清单,能通过编程找到漏掉的是哪1笔或几笔吗?
*/
	public static int sum=6;
	public static int []a={3,2,4,3,1};

	public static void main(String[] args) {
		boolean []b=new boolean [a.length];
		f(0,0,b);
	}

//	对n进行划分
//	a[]用于暂存加数,k当前存储位置
//	k:当前处理的位置上
//	cur_sum:前边的元素累加和
//	b:记录当前项是否被选取
	private static void f(int k,int cur_sum,boolean []b) {
//		出口
		if(cur_sum>sum) return;
		if(cur_sum==sum){
			for (int i = 0; i < b.length; i++) {
				if(!b[i]){
					System.out.print(a[i]+" ");				
				}
			}
			System.out.println();
			return;
		}
		if(k>=a.length) return;
		
//		漏了
		b[k]=false;
		f(k+1,cur_sum,b);
//		没漏
		b[k]=true;
		cur_sum+=a[k];
		f(k+1,cur_sum,b);
//		回溯,默认他是没有被选取的
		b[k]=false;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值