左神算法笔记06:暴力递归

暴力递归

暴力递归就是尝试

  1. 把问题转化为规模缩小了的同类问题的子问题
  2. 有明确的不需要继续进行递归的条件(base case)
  3. 有当得到了子问题的结果之后的决策过程
  4. 不记录每一个子问题的解

一定要学会怎么去尝试,因为这是动态规划的基础

汉诺塔问题

打印n层汉诺塔从最左边移动到最右边的全部过程
在这里插入图片描述
在这里插入图片描述

public class Hanoi {
	public static void hanoi(int n){
		if(n > 0){
			func(n,"左","右","中");
		}
	}
	//1~i 圆盘目标是from->to other是另一个
    public static void func(int i, String start, String end, String other){
    	//base
        if(i == 1){
            System.out.println("move 1 from " + start+ " to " + end);
        }else {
            func(i-1, start,other,end);
            System.out.println("move " + i + " from " + start+ " to " + end);
            func(i-1,other,end,start);
        }
    }

    public static void main(String[] args) {
        hanoi(3);
    }
}

打印一个字符串的全部子序列,包括空字符串

在这里插入图片描述

public class PrintAllSubsequences {
	public static void printAllSubsequences (String str){
		char[] chs = str.toCharArray();
		process(chs,0);
	} 
	//当前来到i位置,要和不要,走两条路
	//之前的选择,所形成的结果,是str
    public static void process(char[] chs,int i){
        if (i == chs.length){
            System.out.println(String.valueOf(chs));
            return;
        }
        //要当前字符的路
        process(chs,i+1);
        char tmp = chs[i];
        chs[i] = 0;
        //不要当前字符的路
        process(chs,i+1);
        chs[i] = tmp;
    }
	
    public static void main(String[] args) {
        String test = "abc";
        printAllSubsequences (test.toCharArray(),0,"");
    }
	//===================================
	public static void function(String str){
		char[] chs = str.toCharArray();
		process(chs,0,new ArrayList<Character>());
	}
	//当前来到i位置,要和不要,走两条路
	//res之前的选择,所形成的列表
	public static void process(char[] str,int i,List<Character> res){
		if(i == str.length){
			printList(res);
			return;
		}
		List<Character> resKeep = copyList(res);
		resKeep.add(str[i]);
		//要当前字符的路
		process(str,i+1,resKeep);
		//不要当前字符的路
		List<Character> resNoInclude = copyList(res);
		process(str,i+1,resNoInclude);
	}
	public static void printList(List<Character> res){
		//自己补充
		
	}
	public static List<Character> copyList(List<Character> list)
	{
		//自己补充
		return null;	
	}

}

打印一个字符串的全部排列

在这里插入图片描述

public class FullPermutation {
    public static void main(String[] args) {
        String str="abc";
        char[] c=str.toCharArray();
        List<String> list=new ArrayList<>();
        process(c,0, list);
        System.out.println(list);
    }
	
	public static ArrayList<String> Permutation(String str){
		ArrayList<String> res = new ArrayList<>();
		if(str == null || str.length() == 0{
			return res;
		}
		char[] chs = str.toCharArray();
		process(chs,0,res);
		return res;

	}
	//str[i..]范围上,所有的字符,都可以在i位置上,后续都去尝试
	//str[0..i-1]范围上,是之前做的选择
	//把所有字符串形成的全排列,加入到res去
    public static void process(char[] str, int i, List<String> res){
        if (i == str.length){
            res.add(String.valueOf(str));
        }
        //为了防止重复全排列
        boolean[] visit = new boolean[26];
        for (int j = i; j <str.length ; j++) {
        	//分支限界
        	if(!visit[str[j]-'a']{
        		visit[str[j]-'a'] = true;
            	swap(str,i,j);
           	 	process(str,i+1,res);
            	swap(str,i,j);
            }
        }
    }

    private static void swap(char[] str, int k, int i) {
        char c=str[k];
        str[k]=str[i];
        str[i]=c;
    }


}

拿牌问题

在这里插入图片描述
在这里插入图片描述

public class Code08_CardsInLine {
 
	public static int win1(int[] arr) {
		if (arr == null || arr.length == 0) {
			return 0;
		}
		return Math.max(f(arr, 0, arr.length - 1), s(arr, 0, arr.length - 1));
	}
 
	public static int f(int[] arr, int i, int j) {
		if (i == j) {
			return arr[i];
		}
		return Math.max(arr[i] + s(arr, i + 1, j), arr[j] + s(arr, i, j - 1));
	}
 
	public static int s(int[] arr, int i, int j) {
		if (i == j) {
			return 0;//后手没有牌可以拿
		}
		return Math.min(f(arr, i + 1, j), f(arr, i, j - 1));
	}
 
	public static int win2(int[] arr) {
		if (arr == null || arr.length == 0) {
			return 0;
		}
		int[][] f = new int[arr.length][arr.length];
		int[][] s = new int[arr.length][arr.length];
		for (int j = 0; j < arr.length; j++) {
			f[j][j] = arr[j];
			for (int i = j - 1; i >= 0; i--) {
				f[i][j] = Math.max(arr[i] + s[i + 1][j], arr[j] + s[i][j - 1]);
				s[i][j] = Math.min(f[i + 1][j], f[i][j - 1]);
			}
		}
		return Math.max(f[0][arr.length - 1], s[0][arr.length - 1]);
	}
 
	public static void main(String[] args) {
		int[] arr = { 1, 9, 1 };
		System.out.println(win1(arr));
		System.out.println(win2(arr));
 
	}
 
}

逆序栈问题

给你一个栈,请你逆序这个栈,不能申请额外的数据结构,只能使用递归函数,如何实现
在这里插入图片描述

public static void reverse(Stack<Integer> stack){
	if(stack.isEmpty(){
		return;
	}
	int i = f(stack);
	reverse(stack);
	stack.push(i);
}
//移除栈底元素并返回
public static int f(Stack<Integer> stack){
	int result = stack.pop();
	if(stack.isEmpty(){
		return result;
	}else{
		int last = f(stack);
		stack.push(result);
		return last;
	}
}

字母和数字对应问题

规定1和A对应,2和B对应,3和C对应。。
那么一个数字字符串比如“111”,就可以转化为“AAA”,“KA”,和“AK”
给定一个只有数字字符组成的字符串str,返回有多少种转化结果
在这里插入图片描述

// i 之前的位置,如何转化已做过决定了
// i... 有多少种转化结果
public static int process(char[] str,int i){
	if(i == str.length){
		return 1;
	}
	if(str[i] == '0'){
		return 0;
	}
	if(str[i] == '1'){
		//i作为单独的部分,后续有多少种方法
		int res = process(str,i+1);
		//i和i+1 一起作为一部分,后续有多少种方法
		if(i + 1 < str.length){
			res += process(str,i+2);
		}
		return res;
	}
	if(str[i] == '2'){
		//i作为单独的部分,后续有多少种方法
		int res = process(str,i + 1);
		//i和i+1 一起作为一部分,并且没有超过26,后续有多少种方法
		if(i + 1 < str.length && str[i + 1] >= '0' && str[i + 1] <= '6')){
			res += process(str,i + 2);
		}
		return res;
	}
	//当前字符是3~9
	return process(str,i + 1);
}

背包问题

给定两个长度都为N的数组weight和values,weight[i]和values[i]分别表示i号物品的重量和价值。给定一个正数bag,表示一个载重bag的袋子,你装的物品不能超过这个重量,返回你能装下的最多的价值是多少

// i..的货物自由选择,形成的最大价值返回
// 重量不要超过bag
// 之前做过的决定所形成的重量,alreadyweight
public static int process1(int[] weight,int[] values,int i,int alreadyweight,int bag){
	if(alreadyweight > bag){
		return 0;
	}
	if(i == weight.lenght){
		return 0;
	}
	return Math.max(
	
	process1(
		// 不要i号货物
		weight,values,i + 1,alreadyweight,bag),
		//要i号货物
		values[i] + process1(weight,values,i + 1,alreadyweight + weight[i],bag) 
	);
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值