算法思维(递归)训练:输出字符串字符的全排列
来源:互联网 发布:网络作家协会怎么加入 编辑:程序博客网 时间:2024/06/05 20:09
题目
设计一个算法,输出一个字符串字符的全排列。 比如,String = “ABC” 输出是
ABC
ACB
BAC
BCA
CBA
CAB
思路
可能我们的第一直觉是,这就是一个选择问题,第一个字符3选1,第二个字符2选1,第三个字符没得选,三层循环可快速暴力求解。可以用嵌套循环来生成新的字符串。
但是这个字符串的长度是不定的,我们没有一种语法可以指定循环的层数。
如果层数根据运行情况来定,唯有递归。
使用递归必须抽象出一个局面x,当下处理一部分使得局面简化为y,递归求解局面y,以此类推,直到问题足够简单可显然求解,然后层层返回。
抽象递归时,我们可以想象我有一个下属,下属又有一个下属,所有这些人都能解决同样的问题。最高层领导只需将局面简化一点点,然后委派下属去处理这个简化后的类似的局面即可,然后就是等结果。
在此题中,我们可以这样考虑:
目标:输出全排列(字符数组) 我来搞定第一个字符 剩下的事,下级来处理剩下的部分 处理到最后一个字符时,就可以输出这个重新排列过的数组了
但很快你会发现,搞定第一个字符有很多种选择,上面的推理需要改写成:
目标:输出全排列(字符数组) 我来搞定第一个字符,这件事我会重复N次,每次选字符串中的一个 一旦选定(把某个字符挪到首位) 剩下的事,下级来处理剩下的部分 因为下次我要再选一个,所以先恢复到挪位之前
那么什么时候输出呢?
这个函数每调用一次,都是上级排好了前面的字符,我来处理后续字符,如果我处理的是最后一个字符,因为上级已经排好前面的,我整体输出全部字符即可。
伪码
// data:上级给任务时字符数组,index:上级已经排好了0~index-1的字符,要我处理index~length-1这段f(char[] data,int index) // 现在我试着从index开始找一个字符来作为首位,我要尝试length-index次 for(int i=index;i<length;i++) swap(data,i,index);// 把i位置的字符交换到index这里来,我的工作就完成了 // 下面请直接下级来接招 f(data,index+1); // 下级排好了,我即将选定下一个字符作为首位,必须先恢复一下 swap(data,i,index); // 如果上级们已经处理好全部字符,我就输出 if(index==length) println(data);
Java代码
package org.lanqiao.algo.recursion;/** * 输出字符串所有字符的全排列 * */public class StrPermutation { static int n; public static void main(String[] args) { String s = "ABCDE"; permutation(s.toCharArray(), 0); System.out.println("---" + n + "---"); // n=长度的阶乘,可以用这个数字验证算法的正确性 } //index代表0~index-1都已确认排列,[index,n-1]待排列 private static void permutation(char[] arr, int index) { //至于什么时候输出,要考虑清楚 //考虑:只有所有位置上的字符都确认即index到达末尾,才算是排好一种情况 if (index == arr.length) { n++; System.out.println(String.valueOf(arr)); } //现在index之前的字符都已就位,把之后的每个字符都交换到index这个位置 for (int k = index; k < arr.length; k++) { //尝试交换 swap(arr, index, k); //交换之后index这个位置就定好了,接下来的事就是递归去解决index+1位置开始的全排列就好了 permutation(arr, index + 1); // 前面我们尝试交换,把全排列求出来了,交换时只尝试了一个字符,因此for循环继续之前要换回来,继续尝试交换下一个字符 swap(arr, index, k); } } private static void swap(char[] arr, int index, int k) { if(k==index) return; // 不必交换了吧 char tmp = arr[k]; arr[k] = arr[index]; arr[index] = tmp; }}
小结
最终代码其实比较简短,这是递归的特点:代码简单,思路绕弯。考验抽象思维和想象力。
使用递归,必须找到问题分解后子问题的相似性,换句话说,你必须找到某种分解结构,按照分解链路可以将问题简化直至可直接得出结论。
阅读全文
0 0
- 算法思维(递归)训练:输出字符串字符的全排列
- 字符串的全排列【递归算法训练】
- 算法思维(递归)训练:输出字符串长度为M的子序列
- 字符全排列的递归算法
- 递归解决输出一个字符串的全排列问题(缺陷:没有考虑字符串中字符重复的问题)
- 求字符串全排列的递归算法
- 求字符串全排列的递归算法
- 字符串全排列问题(递归算法)
- 求字符串全排列的递归算法(java程序)
- JAVA递归和非递归输出字符串的全排列
- 递归复习,递归输出字符串的全排列
- 算法 - 输出一个字符串的全排列(C++)
- 全排列的递归算法(包括字典序输出和非字典序输出)
- 普通递归算法:输出n个数的所有全排列
- 采用递归算法实现任意字符的全排列问题
- 字符串的全排列 递归
- 字符串的全排列和组合算法(递归非递归)
- 输出字符串的所有全排列(递归法和非递归,非递归采用组合数学的字典序)
- poj 1085 Triangle War 极大极小搜索
- 第一次
- git提示 error: Your local changes to the following files would be overwritten by merge:
- restful接口客户端和服务端开发,HttpURLConnection,HttpClient,post ,get方式调用
- C#委托调用过程(实例)
- 算法思维(递归)训练:输出字符串字符的全排列
- 工作中使用ubuntu心得
- 思岚科技让服务机器人移动智能化
- RecyclerView之更新UI数据的高级用法
- ExtJs 获取其他页面的组件方式
- 最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等等
- oracle 11g开启归档模式及修改归档目录
- 1071. 小赌怡情(15)
- Unescaped control character around character