暴力递归1
暴力递归的思路:
利用递归的(深度优先)搜索功能,去枚举一个问题的所有可能情况(或步骤),从而寻求最优解(总答案)
1.汉诺塔问题
* 将问题分为三个步骤,使用递归的方式进行实现。
* 定义一个函数f(from,to,other),from表示圆盘移动的起始杆,to表示圆盘移动的终点杆,other为另一个杆
*
* 递归的思路:
* 1.将上方的1——i-1个圆盘从左圆盘移动到中间圆盘
* 2.将最下方的第i个圆盘从左圆盘移动到右圆盘
* 3.将1——i-1个圆盘从中间圆盘移动到右圆盘
代码及解析:
1 public static void f(int i,String from,String to,String other) {//i表示第几个圆盘 2 if (i == 1) { 3 System.out.println("Move 1 from " + from + " to " + to); 4 } 5 else { 6 f(i - 1,from,other,to); 7 System.out.println("Move " + i + " from " + from + " to " + to); 8 f(i - 1,other,to,from); 9 } 10 } 11 12 public static void hanoi(int n) { 13 if (n > 0) { 14 f(n,"左","中","右"); 15 } 16 } 17 18 public static void main(String[] args) { 19 hanoi(5); 20 }
2.获得并打印输出一个字符串的所有子字符串
* 思路:采用暴力递归
* 对每个字符是否要打印都进行递归式的暴力搜索遍历即可
代码及解析:
1 //法一(较为占用空间) 2 public static void process1(char[] str,int i,List<Character> res) { 3 if (i == str.length) { 4 System.out.println(res); 5 return; 6 } 7 List<Character> resKeep = copyList(res);//保留所有的字符 8 resKeep.add(str[i]); 9 process1(str,i + 1,resKeep);//遍历所有要打印字符的路线 10 List<Character> resNoInclude = copyList(res); 11 process1(str,i + 1,resNoInclude);//遍历所有不打印字符的路线 12 } 13 14 public static List<Character> copyList(List<Character> res) { 15 List<Character> ans = new ArrayList<>(); 16 for (Character c : res) { 17 ans.add(c); 18 } 19 return ans; 20 } 21 22 //法二(重复利用空间) 23 public static void process2(char[] str,int i) { 24 if (i == str.length) { 25 System.out.println(String.valueOf(str)); 26 return; 27 } 28 char tmp = str[i]; 29 process2(str,i + 1);//保留当前位置的字符的路线 30 str[i] = 0;//将该位 置为空 31 process2(str,i + 1);//舍弃当前位置的字符的路线 32 str[i] = tmp;//复原原来的字符串 33 }
3.字符串全排列:
* 暴力递归思想:
* 从第一个字符串开始,可以与后面的任意字符进行交换,交换后再对第二个字符串进行类似的操作,
* 以此类推,直到最后一个字符串,即可得到所有的排列可能
代码及解析:
1 public static ArrayList<String> AllSort(String str) { 2 char[] strs = str.toCharArray(); 3 ArrayList<String> res = new ArrayList<>(); 4 process(strs,0,res); 5 return res; 6 } 7 8 public static void process(char[] str,int i,ArrayList<String> res) { 9 if (i == str.length) { 10 res.add(String.valueOf(str)); 11 return; 12 } 13 boolean[] isVisit = new boolean[26]; 14 for (int j = i; j < str.length; j++) { 15 if (!isVisit[str[j] - 'a']) {//避免出现重复排序的情况 16 isVisit[str[j] - 'a'] = true; 17 swap(str,i,j);//进行遍历交换,得到所有可能的全排列 18 process(str,i + 1,res); 19 swap(str,i,j);//恢复回交换前的状态 20 } 21 } 22 } 23 24 public static void swap(char[] str,int i,int j) { 25 char tmp = str[i]; 26 str[i] = str[j]; 27 str[j] = tmp; 28 }
4.两端取数问题:
A和B两人在数组的两端取数(A先B后),若两者都做最优的选择,返回两者取到的数的总和的最大值
代码及解析:
1 public static int win1(int[] arr) { 2 if (arr == null || arr.length == 0) { 3 return 0; 4 } 5 return Math.max(f(arr,0,arr.length - 1), s(arr,0,arr.length - 1)); 6 } 7 8 public static int f(int[] arr,int L,int R) {//先手者(A)的操作函数 9 if (L == R) {//如果只剩一个数则直接取走 10 return arr[L]; 11 } 12 //先手者有主导权,可以控制自己拿到最好情况(即max) 13 return Math.max(arr[L] + s(arr,L + 1,R), arr[R] + s(arr,L,R - 1)); 14 } 15 16 public static int s(int[] arr,int L,int R) {//后手者(B)的操作函数 17 if (L == R) { 18 return 0; 19 } 20 //因为后手者的选择被先手者控制,所以它只能取到自己的最坏情况(即min) 21 return Math.min(arr[L] + f(arr,L - 1,R), arr[R] + f(arr,L,R - 1)); 22 }
5.递归实现栈的逆序:
* 在使用递归时,要注意每次得取到栈底的元素,才可以实现栈的逆序,所以要先写一个获得栈底元素的方法
代码及解析:
1 public static void reverse(Stack<Integer> stack) { 2 if (stack.isEmpty()) { 3 return; 4 } 5 int i = f(stack);//i为栈底元素 6 reverse(stack); 7 stack.push(i);//将栈底的元素压入到栈中 8 //所以越在底部的元素会越早被取出,也就会被越迟压入栈,所以最底部的元素最终被调整到最顶部。 9 } 10 11 public static int f(Stack<Integer> stack) {//将栈中最底下的元素弹出,并保持栈的原始数据位置 12 int rst = stack.pop(); 13 if (stack.isEmpty()) { 14 return rst; 15 } else { 16 int last = f(stack); 17 stack.push(last); 18 return last; 19 } 20 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端