递归训练题与动态规划
暴力递归:
1,把问题转化为规模缩小了的同类问题的子问题
2,有明确的不需要继续进行递归的条件(base case)
3,有当得到了子问题的结果之后的决策过程
4,不记录每一个子问题的解
动态规划:
1,从暴力递归中来
2,将每一个子问题的解记录下来,避免重复计算
3,把暴力递归的过程,抽象成了状态表达
4,并且存在化简状态表达,使其更加简洁的可能
暴力递归改成动态规划的大致步骤
1、分析可变参数 定下解空间
2、确定最终状态
3、根据base case确定初始状态
4、分析普遍位置依赖哪些
5、根据依赖顺序逆序求整张表
求n!的结果
【Code】
//递归写法
public static long factoria(int n)
{
if(n==1)
return 1L;
return (long)n*factoria(n-1);
}
//非递归写法
public static long Factoria(int n)
{
int result = 0;
for(int i =1;i<=n;i++)
result*=i;
return result;
}
汉诺塔问题
打印n层汉诺塔从最左边移动到最右边的全部过程
【Code】
public static void HannuoTa(int n)
{
if(n>0)
func("left", "mid", "right", n);
}
public static void func(String from,String mid,String to,int n)
{
if(n==1)
System.out.println("move from"+from+"to"+to);
else {
func(from, to, mid, n-1);
func(from, mid, to, 1);
func(mid, from, to, n-1);
}
}
打印一个字符串的全部子序列,包括空字符串
【Code】
public static void printAllstr(char[] chs,int i)
{
if(i==chs.length)
{
System.out.println(String.valueOf(chs));
return;
}
printAllstr(chs, i+1);
char temp = chs[i];
chs[i] = 0;
printAllstr(chs, i+1);
chs[i] = temp;
}
public static void printAllSubsquence(String str) {
char[] chs = str.toCharArray();
printAllstr(chs,0);
}
打印一个字符串的全部排列
【Code】
public static void PrintAllPaiLie(String str)
{
char[] chs = str.toCharArray();
func(chs, 0);
}
public static void func(char[] chs,int i)
{
if(i==chs.length)
System.out.println(String.valueOf(chs));
//如果求全排列中不包含重复的,则使用上hash表
HashSet<Character>map = new HashSet<>();
for(int j = i;j<chs.length;j++)
{
if(!map.contains(j))
{
map.add(chs[j]);
swap(chs,i,j);//在chs中交换下标为i和j两位置的字符
func(chs, i+1);
swap(chs,i,j);
}
}
}
母牛每年生一只母牛,新出生的母牛成长三年后也能每年生一只母牛,假设不会死。求N年后,母牛的数量。
【Code】
public static int cow(int n)
{
if(n<1)
return 0;
if(n==1||n==2||n==3)
return n;
return cow(n)+cow(n-3);
}
如果每只母牛只能活10年,求N年后,母牛的数量。
if(n<10)
return cow(n)+cow(n-3);
else {
return cow(n)+cow(n-3)+cow(n-10);
}
给你一个栈,请你逆序这个栈,不能申请额外的数据结构,只能使用递归函数。如何实现?
【Code】
//逆序栈内容
//使用功能函数每次取栈底元素,再递归式地反向压回栈中
public static void reverse(Stack<Integer> stack)
{
if(stack.isEmpty())
return;
int i = func(stack);
reverse(stack);
stack.push(i);
}
//功能为从栈中取栈底元素
public static int func(Stack<Integer>stack)
{
int result = stack.pop();
if(stack.isEmpty())
return result;
else {
int last = func(stack);
stack.push(result);
return last;
}
}
给你一个二维数组,二维数组中的每个数都是正数,要求从左上角走到右下角,每一步只能向右或者向下。沿途经过的数字要累加起来。返回最小的路径和。
public static int minpath1(int[][] matix) { return process1(matix, matix.length-1, matix[0].length-1); } public static int process1(int[][] matix,int i,int j) { int res = matix[i][j]; if(i==0&&j==0) { return res; } else if(i==0&&j!=0) { return process1(matix, i, j-1)+res; } else if(i!=0&&j==0) { return res +process1(matix, i-1, j); } else { return res+process1(matix, i-1, j-1); } } public static int minpath2(int[][] m) { if(m==null||m[0]==null|| m.length==0 || m[0].length == 0) return 0; int row = m.length; int col = m[0].length; int[][] dp = new int[row][col]; dp[0][0] = m[0][0]; for (int i = 1; i < row; i++) { dp[i][0] = dp[i - 1][0] + m[i][0]; } for (int j = 1; j < col; j++) { dp[0][j] = dp[0][j - 1] + m[0][j]; } for (int i = 1; i < row; i++) { for (int j = 1; j < col; j++) { dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + m[i][j]; } } return dp[row - 1][col - 1]; }
给你一个数组arr,和一个整数aim。如果可以任意选择arr中的数字,能不能累加得到aim,返回true或者false
给定两个数组w和v,两个数组长度相等,w[i]表示第i件商品的重量,v[i]表示第i件商品的价值。再给定一个整数bag,要求你挑选商品的重量加起来一定不能超过bag,返回满足这个条件下,你能获得的最大价值。