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

news/2025/1/16 4:46:47/

算法|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);
}

测试结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xrBorUnz-1685191345292)(F:\typora插图\image-20230527145351725.png)]

2.斐波那契

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

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

核心代码:

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

测试代码及测试结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hKNDL3Br-1685191345293)(F:\typora插图\image-20230527145950490.png)]

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);}
}

测试结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dcRxVADt-1685191345294)(F:\typora插图\image-20230527161900036.png)]

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);}
}

测试结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sR4TWrsf-1685191345294)(F:\typora插图\image-20230527151642604.png)]

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());}
}

测试结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aTAwDm1I-1685191345295)(F:\typora插图\image-20230527162944805.png)]

递归总结

例题总结:

  • 汉诺塔:六个子过程,打印内容为“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),


http://www.ppmy.cn/news/95792.html

相关文章

关于Chrome DevTool

1.基本 打开开发者工具&#xff1a;F12 打开命令菜单&#xff1a;ctrlshiftp DevTool黑色主题&#xff1a;在命令菜单中输入dark theme 截图&#xff1a;命令菜单输入screenshot dock&#xff1a;undock将开发者工具变成一个独立的出口&#xff0c;dock to right 2.Elements面…

RFID安全的三次认证

一.RFID介绍 RFID是Radio Frequency Identification的缩写&#xff0c;即射频识别。它是一种通过用电磁场收集数据并从远距离自动识别物体的技术。它使用无线电波来将信息从一个电子标签传输到读卡器中&#xff0c;而不需要直接接触。这些标签可以嵌入到物品中或附加到物品表面…

权限提升:Mysql 数据库 .(UDF || 启动项 || 反弹)

权限提升&#xff1a;Mysql 数据库. 权限提升简称提权&#xff0c;由于操作系统都是多用户操作系统&#xff0c;用户之间都有权限控制&#xff0c;比如通过 Web 漏洞拿到的是 Web 进程的权限&#xff0c;往往 Web 服务都是以一个权限很低的账号启动的&#xff0c;因此通过 Web…

Python程序员入职后如何做自我介绍,才能让大家记住你

大家好&#xff0c;首先感谢大家能够阅读我的文章。今天我想分享的是关于Python程序员入职公司后做自我介绍的一个模板&#xff0c;希望对大家有所帮助。 做自我介绍是一个很重要的环节&#xff0c;它可以让领导和同事们更好地了解你并且对你产生好感。通常情况下&#xff0c;…

MySQL基于MysqlXADataSource实现分布式事务

最近项目上遇到分布式事务的问题,就对分布式事务重新研究了下,打算整理几篇进行分布式事务的介绍,这个是第二篇,上一篇介绍了基于MySQL命令行实现分布式事务,这一篇介绍不依赖任何ORM框架,只使用mysql-connector-java中自带的MysqlXADataSource实现基于XA协议的分布式事务…

我有一个朋友,分享给我的字节跳动测试开发真题

朋友入职已经两周了&#xff0c;整体工作环境还是非常满意的&#xff01;所以这次特意抽空给我写出了这份面试题&#xff0c;而我把它分享给小伙伴们&#xff0c;面试&入职的经验&#xff01; 大概是在3月中的时候他告诉我投递了简历&#xff0c;5月的时候经过了3轮面试收获…

作业调度FluentScheduler的使用

定时的作业调度工具很多以前用过是Quartz.NET这个&#xff0c;后面也用过FluentScheduler&#xff0c;个人绝对比较好用&#xff0c;所以记录下 老规矩 nuget下载 上代码&#xff0c;一看就懂 static void Main(string[] args){初始化&#xff0c;并执行JobManager.Initializ…

【Netty】Netty 编解码器(十四)

文章目录 前言一、编解码器概述二、ByteToMessageCodec 抽象类三、MessageToMessageCodec 抽象类四、ChannelDuplexHandler 类五、CombinedChannelDuplexHandler 类总结 前言 回顾Netty系列文章&#xff1a; Netty 概述&#xff08;一&#xff09;Netty 架构设计&#xff08;…