详解暴力递归

 

目录

 

【汉诺塔问题】:​编辑

【打印字符串子序列: (包括空字符串)】

【打印字符串的全部排列: (不能出现重复的排列)】

给定一个整型数组arr,代表数值不同的纸牌排成一条线

玩家A和玩家B依次拿走每张纸牌

规定玩家A先拿,玩家B后拿

但是每个玩家每次只能拿走最左或最右的纸牌

玩家A和玩家B都绝顶聪明

请返回最后获胜者的分数

 给你一个栈,请你逆序这个栈,不能申请额外的数据结构,只能使用递归函数。

 规定1和A对应、2和B对应、3和C对应…26和Z对应,那么一个数字字符串比如"111”就可以转化为:“AAA”、“KA"和"AK”。给定一个只有数字字符组成的字符串str,请问有多少种转化结果?

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

返回你能装下的的最大价值是多少?


【汉诺塔问题】:

 

/**
 * @ProjectName: study3
 * @FileName: TowerOfHanoi
 * @author:HWJ
 * @Data: 2023/6/12 10:09
 */
public class TowerOfHanoi {
    public static void main(String[] args) {
        int n = 3;
        hanoi(3);
    }

    public static void hanoi(int n){
        if (n > 0){
            func(n, "左", "右", "中");
        }
    }

    public static void func(int i, String start, String end, String other){
        if (i == 1){
            System.out.println("Move " + i + " 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);
        }
    }
}

【打印字符串子序列: (包括空字符串)】

 

import java.util.ArrayList;
import java.util.List;

/**
 * @ProjectName: study3
 * @FileName: PrintAllSubsquences
 * @author:HWJ
 * @Data: 2023/6/12 10:28
 */
public class PrintAllSubsquences {
    public static void main(String[] args) {
        String str = "abc";
        function(str);
        System.out.println("---------------------");
        printAll(str);
    }

    public static void function(String str){
        char[] charArray = str.toCharArray();
        process(charArray, 0, new ArrayList<>());
    }

    public static void process(char[] chars, int i, List<Character> res){
        if (i == chars.length){
            printList(res);
        }else {
            List<Character> have = copyList(res);
            have.add(chars[i]);
            process(chars, i+1, have); // 要当前字符
            List<Character> notHave = copyList(res);
            process(chars, i+1, notHave); // 不要当前字符
        }
    }

    public static void printList(List<Character> res){
        for (char c :res) {
            System.out.print(c);
        }
        System.out.println();
    }

    public static List<Character> copyList(List<Character> res){
        ArrayList<Character> list = new ArrayList<>(res);
        return list;
    }


    //-----------------------------------------------------------------------------------
    // 方法二
    public static void printAll(String str){
        char[] charArray = str.toCharArray();
        process(charArray, 0);
    }

    public static void process(char[] chars, int i){
        if (i == chars.length){
            System.out.println(String.valueOf(chars));
            return;
        }
        process(chars, i+1); // 要当前字符的路
        char tmp = chars[i];
        chars[i] = 0;
        process(chars, i+1); // 不要当前字符的路
        chars[i] = tmp;
    }
}

【打印字符串的全部排列: (不能出现重复的排列)】

 

import java.util.ArrayList;
import java.util.List;

/**
 * @ProjectName: study3
 * @FileName: PrintAllPermutations
 * @author:HWJ
 * @Data: 2023/6/12 11:06
 */
public class PrintAllPermutations {
    public static void main(String[] args) {
        String str = "aabc";
        printALl(str);


    }

    public static void printALl(String str) {
        char[] charArray = str.toCharArray();
        ArrayList<String> res = new ArrayList<>(); // 用res来记录所有全排列结果
        process(charArray, 0, res);
        printList(res);
    }

    public static void process(char[] chars, int i, ArrayList<String> res) {
        if (i == chars.length) {
            res.add(String.valueOf(chars));
            return;
        }
        /**
         * boolean[] bools = new boolean[26];
         * if (!bools[chars[j] - 'a']){
         * // 加入这个的含义是一个字符串中 可能有多个相同的字符,他们交换到同一个位置的作用是一样的
         * // 可能会造成全排列的重复
         *  bools[chars[j] - 'a'] = true;
         *  swap(chars, i, j);
         *  process(chars, i+1, res); // 当找到一个全排列后,要重新交换,使数组还原,已使下一次得到正确的全排列
         *  swap(chars, i, j);
         *  }
         */
        boolean[] bools = new boolean[26];
        for (int j = i; j < chars.length; j++) {
            if (!bools[chars[j] - 'a']) {
                bools[chars[j] - 'a'] = true;
                swap(chars, i, j);
                process(chars, i + 1, res); // 当找到一个全排列后,要重新交换,使数组还原,已使下一次得到正确的全排列
                swap(chars, i, j);
            }

        }
    }

    public static void swap(char[] chars, int i, int j) {
        char tmp = chars[i];
        chars[i] = chars[j];
        chars[j] = tmp;
    }
    public static void printList(List<String> res){
        for (String c :res) {
            System.out.println(c);
        }

    }

}

给定一个整型数组arr,代表数值不同的纸牌排成一条线

玩家A和玩家B依次拿走每张纸牌

规定玩家A先拿,玩家B后拿

但是每个玩家每次只能拿走最左或最右的纸牌

玩家A和玩家B都绝顶聪明

请返回最后获胜者的分数

 

/**
 * @ProjectName: study3
 * @FileName: Win
 * @author:HWJ
 * @Data: 2023/6/12 12:38
 */
public class Win {
    public static void main(String[] args) {
        int[] arr = {1,2,100,4};
        System.out.println(win(arr));
    }
    public static int win(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 l, int r){
        if (l == r){ // 如果是最后一张排,因为是先手,就可以拿到这张牌,返回这张牌
            return arr[l];
        }
        return Math.max(arr[l] + s(arr, l+1, r), arr[r] + s(arr, l, r-1));
    }

    public static int s (int[] arr, int l, int r){
        if (l == r){ // 如果是最后一张排,因为是后手,就无法拿到这张牌,返回0
            return 0;
        }
        // 返回对手已经拿了一张牌
        // 此时我们便变为后手,
        // 因为对面先手,一定会拿对自己有利的牌,我们就无法拿到有利的牌,所以我们只能拿到最小的牌中对自己有利的牌
        return Math.min(f(arr, l+1, r), f(arr, l, r-1));
    }
}

 给你一个栈,请你逆序这个栈,不能申请额外的数据结构,只能使用递归函数。

import java.util.Stack;

/**
 * @ProjectName: study3
 * @FileName: ReverseStack
 * @author:HWJ
 * @Data: 2023/6/12 13:01
 */
public class ReverseStack {
    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>(); // 堆栈是后进先出,如果没有逆序,应打印 5 4 3 2 1
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.push(5);
        while (!stack.isEmpty()){
            System.out.println(stack.pop());
        }
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.push(5);
        reverse(stack);
        System.out.println("----------reverse---------");
        while (!stack.isEmpty()){
            System.out.println(stack.pop());
        }
    }

    public static void reverse(Stack<Integer> stack){
        if (stack.isEmpty()){
            return;
        }
        int res = remove(stack);
        reverse(stack);
        stack.push(res);
    }

    // 移除一个栈中的最后一个元素,其他的栈元素整体往下移
    public static int remove(Stack<Integer> stack){
        int res = stack.pop();
        if (stack.isEmpty()){
            return res;
        }else {
            int last = remove(stack);
            stack.push(res);
            return last;
        }
    }
}

 规定1和A对应、2和B对应、3和C对应…26和Z对应,那么一个数字字符串比如"111”就可以转化为:“AAA”、“KA"和"AK”。给定一个只有数字字符组成的字符串str,请问有多少种转化结果?

/**
 * @ProjectName: study3
 * @FileName: NumToStr
 * @author:HWJ
 * @Data: 2023/6/12 14:31
 */
public class NumToStr {
    public static void main(String[] args) {

    }

    public static int translate(String str){
        char[] charArray = str.toCharArray();
        return process(charArray, 0);
    }

    public static int process(char[] str, int i){
        if ( i == str.length){ // 如果已经把所有的都决定完了,返回1
            return 1;
        }
        if (str[i] == '0'){ // 如果第i位为0,没法转换,返回0
            return 0;
        }
        if (str[i] == '1'){
            int res = process(str, i+1);  // i 自己作为单独的部分,后续有多少种方法,
            if (i+1 < str.length){
                res += process(str, i+2);// (i 和 i+1) 自己作为单独的部分,后续有多少种方法
            }
            return res;
        }
        if (str[i] == '2'){
            int res = process(str, i+1); // i 自己作为单独的部分,后续有多少种方法,
            if (i+1 < str.length && str[i+1] >= '0' && str[i+1] <= '6'){ // (i 和 i+1) 自己作为单独的部分,后续有多少种方法,
                res += process(str, i+2);   // 明确要求其不能超过26
            }
            return res;
        }
        return process(str, i+1);
    }
}

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

返回你能装下的的最大价值是多少?

从左往右依次考虑每个商品要还是不要,然后就得到了所有情况,再不断递归找最大。

/**
 * @ProjectName: study3
 * @FileName: getMaxValue
 * @author:HWJ
 * @Data: 2023/6/12 14:52
 */
public class getMaxValue {
    public static void main(String[] args) {

    }

    public static int search(int[] weights, int[] values, int bag){
       //return process(weights, values, 0, 0, 0,bag);
        return process2(weights, values, 0,0,bag);
    }

    public static int process(int[] weights, int[] values, int i, int alreadyWeight, int alreadyValue, int bag){
        // 方法和下一个类似, 但下一个更好
        if (i == weights.length){
            return alreadyValue;
        }
        if (alreadyWeight > bag){
            return 0;
        }
        return Math.max(
                process(weights, values, i+1, alreadyWeight, alreadyValue, bag),
                process(weights, values, i+1, alreadyWeight+weights[i], alreadyValue+values[i], bag)
        );
    }

    public static int process2(int[] weights, int[] values, int i, int alreadyWeight, int bag){
        if (i == weights.length){
            return 0;
        }
        if (alreadyWeight > bag){
            return 0;
        }
        return Math.max(
                process2(weights, values, i+1, alreadyWeight, bag), // 不要这个商品
                values[i] + process2(weights, values, i+1, alreadyWeight+weights[i], bag) //要这个商品,
                // 不断递归,相当于依次对所有商品进行了要和不要两种的考虑,然后再依次找最大。
        );
    }

}

 // 暴力递归时的原则:找到可变参数形式最简单,可变参数个数最少的方法

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Studying~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值