算法7.从暴力递归到动态规划0

这篇具有很好参考价值的文章主要介绍了算法7.从暴力递归到动态规划0。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

算法|7.从暴力递归到动态规划0

1.汉诺塔

题意:打印n层汉诺塔从最左边移动到最右边的全部过程

解题思路:

  • 把字母抛掉,变成左中右三个盘子
  • 多个盘子能一下到吗?不能,把上边的拿走,最下边的才能放到指位置(leftToRight)
  • 上边的怎么拿,leftToMid。那它具体怎么拿,midToLeft…如此,需要6个子过程
  • 他们之间互相调用,能够满足

核心代码:

public static void hanio(int n){
    leftToRight(n);
}
private static void leftToRight(int n) {
    if(n==1){
        System.out.println("Move 1 from left to right");
        return ;
    }
    leftToMid(n-1);
    System.out.println("Move "+n+" from left to right");
    midToRight(n-1);
}

private static void midToRight(int n) {
    if(n==1){
        System.out.println("Move 1 from mid to right");
        return ;
    }
    midToLeft(n-1);
    System.out.println("Move "+(n)+" from mid to right");
    leftToRight(n-1);
}
private static void leftToMid(int n) {
    if(n==1){
        System.out.println("Move 1 from left to mid");
        return ;
    }
    leftToRight(n-1);
    System.out.println("Move "+(n)+" from left to mid");
    rightToMid(n-1);
}

private static void rightToMid(int n) {
    if(n==1){
        System.out.println("Move 1 from right to mid");
        return ;
    }
    rightToLeft(n-1);
    System.out.println("Move "+(n)+" from right to mid");
    leftToMid(n-1);
}

private static void rightToLeft(int n) {
    if(n==1){
        System.out.println("Move 1 from right to left");
        return ;
    }
    rightToMid(n-1);
    System.out.println("Move "+(n)+" from right to left");
    midToLeft(n-1);
}

private static void midToLeft(int n) {
    if(n==1){
        System.out.println("Move 1 from mid to left");
        return ;
    }
    midToRight(n-1);
    System.out.println("Move "+(n)+" from mid to left");
    rightToLeft(n-1);
}

测试代码

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

测试结果:算法7.从暴力递归到动态规划0

2.斐波那契

题意:求斐波那契数列第n项数

**解题思路:**略(之前写过)

核心代码:

private static int fib(int n) {
    if(n==1||n==2){
        return 1;
    }
    return fib(n-1)+fib(n-2);
}

测试代码及测试结果:算法7.从暴力递归到动态规划0

3.打印全排列(去重+不去重)

题意:1.打印一个字符串的全部排列 2.打印一个字符串的全部排列,要求不要出现重复的排列

解题思路:

  • 当前位置和其他位置交换
  • 清除/恢复现场
  • 当前位置为index~N-1
  • 其他位置index+1到N-1
  • 产生的结果个数为n!个
  • 这里也是,如果字符串为空,也产生结果,不过产生的结果是空串
  • 注意:这里没有再用路径,而是使用的自己,所以加入结果集的时候是String.valueOf(str)
  • 去重的思路有两种:过滤式、剪枝式,过滤即使用去重的集合,这里的剪枝策略则是使用visit数组(因为是字符串,所以大小定为256),判断这个元素在这个位置有没有出现过,若出现过则直接跳下一个

核心代码:

/**
 * 设置更为合适的参数
 *这里老师讲的版本没有再传中间参数,而是自己玩自己,相邻的交换,之后再恢复现场
 * @param test
 * @return
 */
private static List<String> permutation(String test) {
    char[] str=test.toCharArray();
    String path="";
    List<String > list=new ArrayList<>();
    process1(str,0,list);
    return list;
}

private static void process1(char[] str, int index, List<String> list) {
    if(index==str.length){
        list.add(String.valueOf(str));
        return ;
    }
    for (int i = index; i < str.length; i++) {
        swap(str,index,i);
        process1(str,index+1,list);
        swap(str,index,i);
    }
}

private static void swap(char[] str, int a, int b) {
    char tmp=str[a];
    str[a]=str[b];
    str[b]=tmp;
}

/**
 * 剪枝的方式去重,提前终止,效率更高
 * @param test
 * @return
 */
private static List<String> noRepeatpermutation1(String test) {
    char[] str=test.toCharArray();
    String path="";
    List<String > list=new ArrayList<>();
    process2(str,0,list);
    return list;
}

private static void process2(char[] str, int index, List<String> list) {
    if(index==str.length){
        list.add(String.valueOf(str));
        return ;
    }
    boolean[] visit=new boolean[256];
    for (int i = index; i < str.length; i++) {
        if(!visit[str[i]]){
            swap(str,index,i);
            process2(str,index+1,list);
            swap(str,index,i);
            visit[str[i]]=true;
        }
    }
}

/**
 * 过滤方式去重
 * @param test
 * @return
 */
private static HashSet<String> noRepeatpermutation2(String test) {
    char[] str=test.toCharArray();
    String path="";
    HashSet<String> set=new HashSet<>();
    process3(str,0,set);
    return set;
}

private static void process3(char[] str, int index, HashSet<String> set) {
    if(index==str.length){
        set.add(String.valueOf(str));
        return ;
    }
    for (int i = index; i < str.length; i++) {
        swap(str,index,i);
        process3(str,index+1,set);
        swap(str,index,i);
    }
}

测试代码

public static void main(String[] args) {
    String test="acc";
    List<String> ans1=permutation(test);
    List<String> ans2=noRepeatpermutation1(test);
    HashSet<String> ans3=noRepeatpermutation2(test);

    System.out.println("未去重");
    for (String str:ans1) {
        System.out.println(str);
    }
    System.out.println("================");
    System.out.println("剪枝版去重");
    for (String str:ans2) {
        System.out.println(str);
    }
    System.out.println("过滤版去重");
    for(String str:ans3){
        System.out.println(str);
    }
}

测试结果:算法7.从暴力递归到动态规划0

4.打印全部子序列(去重+不去重)

题意:1.打印一个字符串的全部子序列 2.打印一个字符串的全部子序列,要求不要出现重复字面值的子序列

解题思路:

  • 数组为空也产生,结果不过是空集
  • 在数组指针走到头了,收集结果
  • path跟着一块玩

核心代码:

private static List<String> subs(String test) {
    char[] str=test.toCharArray();//空的话也产生,不过是一个空串
    String path="";
    List<String> ans=new ArrayList<>();
    process1(str,0,ans,path);
    return ans;
}
private static void process1(char[] str, int index, List<String> list, String path) {
    if(index==str.length){
        list.add(path);
        return ;
    }
    process1(str,index+1,list,path+str[index]);
    process1(str,index+1,list,path);
}

/**
 * 去重版本
 * @param test
 * @return
 */
private static HashSet<String> subsNoRepeat(String test) {
    char[] str=test.toCharArray();//空的话也产生,不过是一个空串
    String path="";
    HashSet<String> set=new HashSet<>();
    process2(str,0,set,path);
    return set;
}

private static void process2(char[] str, int index, HashSet<String> set, String path) {
    if(index==str.length){
        set.add(path);
        return ;
    }
    process2(str,index+1,set,path+str[index]);
    process2(str,index+1,set,path);

}

测试代码:

public static void main(String[] args) {
    String test="acc";
    List<String> ans1=subs(test);
    HashSet<String> ans2= subsNoRepeat(test);

    for(String str:ans1){
        System.out.println(str);
    }
    System.out.println("===============");
    for(String str:ans2){
        System.out.println(str);
    }
}

测试结果:算法7.从暴力递归到动态规划0

5.使用递归逆序栈

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

解题思路:

  • 栈底的元素不断移除——成为返回值交给系统栈(子过程的栈)
  • 子函数功能:移除栈底元素,上边的元素盖下来,返回移除的 栈顶元素

核心代码:

private static void reverse(Stack<Integer> stack) {
    if(stack.isEmpty()){
        return ;
    }
    int tmp=f(stack);
    reverse(stack);
    stack.push(tmp);
}
//f函数的功能是栈底元素移除掉
//上边的元素盖下来,返回移除的栈顶元素
private static int f(Stack<Integer> stack) {
    int ans=stack.pop();
    if(stack.isEmpty()){
        return ans;
    }else{
        int last=f(stack);
        stack.push(ans);
        return last;
    }
}

测试代码:

public static void main(String[] args) {
    Stack<Integer> stack=new Stack<>();
    stack.push(1);
    stack.push(2);
    stack.push(3);
    stack.push(4);
    stack.push(5);
    reverse(stack);
    while(!stack.isEmpty()){
        System.out.println(stack.pop());
    }
}

测试结果:算法7.从暴力递归到动态规划0

递归总结

例题总结:

  • 汉诺塔:六个子过程,打印内容为“Move ”+n +“from xx to xxx”

  • 斐波那契:无话可说,1||2||n-1||n-2

  • 打印全部子序列:非去重:str,index,list,path,到头了加入,要与不要;去重:使用HashSet过滤,只是换了一种收集容器

  • 打印全排列:

    总体思路,自己玩自己的(当前位置和可能成为当前位置的元素进行交换n!种可能)先交换,去下个位置,再回复现场(for循环)

    非去重:str,index,list

    去重:剪枝:拜访数组,256,判断当前字符在这个位置出现过没,出现过就要,没出现过就不要;过滤:换了个收集容器HashSet

  • 使用递归逆序栈(不申请额外数据结构):f的功能拿栈底元素:if,ans,else last,push(ans),文章来源地址https://www.toymoban.com/news/detail-479866.html

到了这里,关于算法7.从暴力递归到动态规划0的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 暴力递归到动态规划(四)

    ⭐️ 前言 ⭐️ 本篇文章是从暴力递归到动态规划篇目的最后一篇文章,包含了几道题目还有最终的大总结,相信这篇文章能让各位读者对动态规划有更深一步的了解。 🍉 欢迎点赞 👍 收藏 ⭐ 留言评论 📝 私信必回哟 😁 🍉 博主将持续更新学习记录收获,友友们有任何问

    2024年02月08日
    浏览(30)
  • 暴力递归到动态规划(三)

    ⭐️ 前言 ⭐️ 本篇文章是从暴力递归到动态规划的第三章。 🍉 欢迎点赞 👍 收藏 ⭐ 留言评论 📝 私信必回哟 😁 🍉 博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言 🍉 博客中涉及源码及博主日常练习代码均已上传GitHub 题目: 给定一个二维数组mat

    2024年02月09日
    浏览(27)
  • 左程云 Java 笔记--暴力递归--动态规划

    暴力递归就是尝试 1,把问题转化为规模缩小了的同类问题的子问题 2,有明确的不需要继续进行递归的条件(base case) 3,有当得到了子问题的结果之后的决策过程, 4,不记录每一个子问题的解 打印n层汉诺塔从最左边移动到最右边的全部过程 打印一个字符串的全部子序列,包

    2023年04月08日
    浏览(36)
  • 一篇文章带你搞懂动态规划(由暴力递归到动态规划)

    ”动态规划“ 的过程相当于 记忆化搜索 , 即在普通 递归 的过程中用二维数组进行记忆化存储一些状态结果, 从而避免重复的计算(剪枝)。 举一个简单的例子:在 递归法 求解 斐波那契 数列的过程中, 就进行了多次的 重复计算 , 而动态规划相当于是对已经计算的状态

    2024年02月20日
    浏览(44)
  • 题解 | #上台阶#C++暴力动态规划解法,非递归

    25届想找实习求看看简历 英伟达笔试 Nvidia24秋招 英伟达嵌入式软件工程师笔试 9-26 2022-08-17-nvidia实习 我发现算法岗也不很难进啊(深度学习) 我发现算法岗也不很难进啊(深度学习) 顺丰科技 1.30校招实习招聘信息汇总 2024春招汇总 『 哨哥的校园招聘周报 』02/05 - 02/18 深圳银河创

    2024年02月21日
    浏览(28)
  • 爬楼梯问题-从暴力递归到动态规划(java)

    一个总共N 阶的楼梯(N 0) 每次只能上一阶或者两阶。问总共有多少种爬楼方式。 示例1: N = 1, 一步上去了,返回1. 示例2: N = 2时。 可以第一次上一阶,再上一阶,这是一种方式, 也可以一次直接上两阶,这也是一种方式, 返回 2; 示例3: N = 3: 可以选择, 1 1 1, 1

    2024年02月10日
    浏览(27)
  • 【LeetCode:72. 编辑距离 | 暴力递归=>记忆化搜索=>动态规划 】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2024年02月06日
    浏览(31)
  • 【LeetCode:64. 最小路径和 | 暴力递归=>记忆化搜索=>动态规划 】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2024年02月05日
    浏览(31)
  • 零钱兑换,凑零钱问题,从暴力递归到动态规划(java)

    322 零钱兑换 - 可以打开链接测试 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。 你可以认为每种硬币的数量是无限的。 示例 1:

    2024年02月07日
    浏览(28)
  • 【LeetCode: 44. 通配符匹配 | 暴力递归=>记忆化搜索=>动态规划 】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域优质创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2024年02月06日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包