暴力递归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     }
复制代码

 

posted @   jue1e0  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示