递归训练题与动态规划

暴力递归:
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,返回满足这个条件下,你能获得的最大价值。
 
 
 
 
posted @ 2021-02-07 20:44  γGama  阅读(87)  评论(0编辑  收藏  举报