黑马程序员技术交流社区

标题: 关于组合问题之递归解决 [打印本页]

作者: 老二    时间: 2014-6-20 21:04
标题: 关于组合问题之递归解决
原始字符串是"abc",打印得到下列所有组合情况:
                "a" "b" "c"
                "ab" "bc" "ca" "ba" "cb" "ac"
                "abc" "acb" "bac" "bca" "cab" "cba"
代码:
public static String str="abc";
         public static void show(int current_recur, String temp) {
                if (current_recur < str.length()) {
                    for (int i = 0; i < str.length(); i++) {
                        if (!(temp.contains(str.substring(i, i + 1)))) {
                            System.out.print(temp + str.substring(i, i + 1) + "    ");
                            show(current_recur + 1,
                                    new String(temp + str.substring(i, i + 1)));
                        }
                    }
                }
         }
作者: 老二    时间: 2014-6-20 21:06
如果把字符串转换成字符数组,应该还有好的解法,更清晰。
作者: 老二    时间: 2014-6-20 21:07
求大神,给思路
作者: 、海    时间: 2014-6-20 21:11
看得很累!
作者: 老二    时间: 2014-6-20 22:19
、海 发表于 2014-6-20 21:11
看得很累!

是啊,一些嵌套,几层for循环
作者: java木    时间: 2014-6-20 23:11
这个我觉得很难,我想了十个小时,尽然还没弄出来。发现用递归来组合,只要超过8个几乎要算很久。
作者: Aron    时间: 2014-6-21 00:02
给你一个我的方法有注释 看你理解不 不懂得就问我
  1. //初始化一个字符串
  2.         private static String s="abcd";
  3.         //把这个字符串中每个字母放入一个数组中
  4.         public static void intoArr(String s,String[] array){
  5.                 for(int i=0;i<s.length();i++){
  6.                         array[i]=String.valueOf(s.charAt(i));
  7.                 }
  8.         }
  9.         private static String[] array =new String[s.length()]; //初始化一个数组
  10.         private static ArrayList<String> pp = new ArrayList<String>(); //定义一个集合用来放最后组合的字符数组
  11.         public static void main(String[] args)
  12.         {
  13.                 intoArr(s,array); //给array赋值
  14.                 execute(); //执行
  15.         }
  16.         //输出和递归调用
  17.         public static void execute()
  18.         {
  19.                 ArrayList<String> list = new ArrayList<String>();
  20.                 //创建包含字符串数组内容的list集合
  21.                 list.addAll(Arrays.asList(array));
  22.                 for (int len = 1; len <= array.length; len++)
  23.                 {       
  24.                         for(String a:pp){
  25.                                 System.out.print(a+" ");
  26.                         }
  27.                         if(len!=1){//第一次不换行
  28.                                 System.out.println();
  29.                         }
  30.                         pp.clear();
  31.                         digui(list, "", len);
  32.                 }
  33.                 for(String a:pp){
  34.                         System.out.print(a+" ");
  35.                 }
  36.         }
  37.         //递归得到组合
  38.         public static void digui(ArrayList<String> list, String result, int len)
  39.         {
  40.                 for (int i = 0; i < list.size(); i++)
  41.                 {
  42.                         String str = list.get(i);
  43.                         result += str;
  44.                         if (result.length() == len)
  45.                                 {
  46.                                         pp.add(result); //把组合放入pp中
  47.                                 }
  48.                         else
  49.                                 {
  50.                                         ArrayList<String> copylist = (ArrayList<String>) list.clone();//克隆一个一样的字符串数组
  51.                                         copylist.remove(str);//把这个复制的字符串数组中的str元素去掉
  52.                                         digui(copylist, result, len);//再次调用递归
  53.                                 }
  54.                         result = result.substring(0, result.length() - 1);//截取掉相对应的字符
  55.                 }
  56.         }
复制代码

这个方法只适合字符串少 如果太大 java会运行不了 所以如果想实现快速的方法 可能要换一种思想
作者: qq474249147    时间: 2014-6-21 00:32
这么短?我写的是无限长度不重复字符串的全组合
作者: 黎志勇    时间: 2014-6-21 06:59
本帖最后由 黎志勇 于 2014-6-21 07:06 编辑

睡前看到这题,睡觉时一直在想,老感觉不舒坦,就起床熬夜写出来了,不写完总睡不着,终于可以安心去睡觉了。
  1. /*思路:
  2. *1.题中所有组合,其实就是带顺序的“3选1”、“3选2”、“3选3”的所有组合;
  3. *2.可以想象abc为三个球,有两个管子,一个用来存已选择的,一个用来存未选择的;
  4. *3.所以可以定义两个字符数组,一个是已被选择的数组selected,一个是待选择的数组toSelect,只要操作这两个数组就OK了;
  5. *4.一开始没选择,已选择数组长度为0,待选择数组长度为3;
  6. *5.选一个字符放进已选择数组,这时已选择数组长度为1,待选择数组长度为2;
  7. *6.每选择一次,打印已选择数组的序列;
  8. *7.重复5、6步,直到未选择数组长度为0;
  9. *
  10. */

  11. public class Demo {
  12.         
  13.         public static void main(String[] args) {
  14.                 show("abc");
  15.         }
  16.         
  17.         //把“选择”操作封装,使满足打印任意非重复字符串组合
  18.         public static void show(String str){
  19.                 selectChar(new char[0],str.toCharArray());
  20.         }
  21.         
  22.         //这个方法是对“选择”这个动作的抽象,对俩数组进行操作
  23.         private static void selectChar(char[] selected,char[] toSelect){
  24.                 if(toSelect.length==0){//如果待选择数组长度为0,则退出选择操作
  25.                         return;
  26.                 }
  27.                 //定义一个新的临时数组,作为新的“已选择数组”,注意新的数组比旧的长度增加1
  28.                 char[] tempSelected = updateSelectedCharArray(selected);//
  29.                 char[] tempToSelect;//新的待选择数组
  30.                 for(int i=0;i<toSelect.length;i++){
  31.                         tempSelected[tempSelected.length-1]=toSelect[i];//把选择的字符放进新“已选择数组”最后 一位
  32.                         tempToSelect=updateToSelecteCharArray(toSelect, i);//更新“待选择数组”
  33.                         System.out.println(String.valueOf(tempSelected));//打印“已选择数组”
  34.                         selectChar(tempSelected, tempToSelect);//重复选择操作
  35.                 }
  36.                
  37.         }
  38.         
  39.         //这个方法用来更新选择一个字符时,“已选择数组”的内容
  40.         private static char[] updateSelectedCharArray(char[] array){
  41.                 char[] temp = new char[array.length+1];
  42.                 for(int i =0;i<array.length;i++){
  43.                         temp[i]=array[i];
  44.                 }
  45.                 return temp;
  46.         }
  47.         //这个方法用来更新选择一个字符后,“待选择数组”的内容
  48.         private static char[] updateToSelecteCharArray(char[] array,int index){
  49.                 char[] temp = new char[array.length-1];
  50.                 for(int i =0,j=0;i<array.length;i++){
  51.                         if(i!=index){
  52.                                 temp[j++]=array[i];
  53.                         }
  54.                 }
  55.                 return temp;
  56.         }
  57.         
  58. }
复制代码




作者: 老二    时间: 2014-6-21 11:53
黎志勇 发表于 2014-6-21 06:59
睡前看到这题,睡觉时一直在想,老感觉不舒坦,就起床熬夜写出来了,不写完总睡不着,终于可以安心去睡觉了 ...

嗯嗯,向你学习
作者: 黎志勇    时间: 2014-6-21 12:13
老二 发表于 2014-6-21 11:53
嗯嗯,向你学习

不过没有这个的输出顺序不像题目标的那样,先输出一个的,再输出两个的,最后三个的,不知道有没有要求输出顺序一定要字符个数要从小到大了。
作者: crazystraw    时间: 2014-6-21 13:22
下面的是我的思路,代码和楼主一样

  1. /*
  2. * 思路:
  3. * 题目相当于要求一个字符串的所有子集(元素位置不相同视为不同子集),
  4. * 此时想到了字符串的substring方法,首先要对怎么取子集进行思考。
  5. * 可以先固定其中一个字符,此字符必然是其中一种组合,
  6. * 然后取原字符串的任意一个字符,如果这两个字符不相同,那么这两个字符形成一个字符,也必然是原字符串的子集
  7. * 然后固定这两个字符形成的字符串,再取原字符串的任意一个字符,如果与这两个字符仍然不同,
  8. * 那么固定这两个字符再加上此字符仍然是所求的,继续固定这三个字符,之后继续循环,
  9. * 如果字符长度等于题目所给字符串长度则停止,返回上一层循环。
  10. * 步骤:
  11. * 通过思路可以看出,该程序需要用到循环和递归的方法。
  12. *
  13. */
  14. public class Text7 {
  15.         public static String str = "abc";//定义一个静态的,可供调用的需要打印子集的原始字符串
  16.        
  17.         public static void show(int length,String fixedStr){   //定义接收两个变量的功能函数
  18.                  //固定的字符串的长度需要小于原始字符串的长度,如果大于,则此循环或者递归中的循环结束,初始固定的字符串视为空
  19.                 if(length<str.length()){  
  20.                         for(int x = 0;x < str.length();x++){   //x为原字符串一个子集的起始角标位
  21.                                 if(!fixedStr.contains(str.substring(x, x+1))){//如果固定的字符串不含有原字符串的其中一个单元素子集的元素
  22.                                         System.out.println(fixedStr+str.substring(x,x+1));//把固定的字符串加上原字符串的第x个元素合在一起打印
  23.                                         show(length+1,new String(fixedStr+str.substring(x,x+1)));//再把打印的这个元素和它的长度作为变量进行递归操作
  24.                                 }
  25.                         }
  26.                 }
  27.                
  28.         }
  29.         public static void main(String[] args){
  30.                 show(0,new String());//可以视为传入一个空字符串,字符串为0长度的参数调用函数打印原始字符串的全字符组合。
  31.         }
  32.        
  33. }
复制代码

作者: 老二    时间: 2014-6-23 08:49
crazystraw 发表于 2014-6-21 13:22
下面的是我的思路,代码和楼主一样

你的注释多,不错
作者: lwh316658735    时间: 2014-12-21 19:00
今天写的可以参考下
  1. import java.util.HashMap;
  2. import java.util.Iterator;
  3. import java.util.Map;
  4. import java.util.Set;
  5. import java.util.TreeSet;
  6. class ForTest3 {
  7.         public static void main(String[] args) {
  8.                 StringBuffer str = new StringBuffer("abc");
  9.                 Set<String> set = new TreeSet<String>();
  10.                 char[] ch = str.toString().toCharArray();
  11.                 print(ch, new StringBuffer(), set, 0);

  12.                 System.out.println();
  13.                 System.out.println("----------------");

  14.                 Set<String> set2 =quChongFu(set);
  15.                 Iterator<String> it2 = set2.iterator();
  16.                 while (it2.hasNext()) {
  17.                         System.out.print(it2.next() + ",");
  18.                 }
  19.         }
  20.         //去掉集合中重复的元素
  21.         /*
  22.          * set:需要除去重复字符元素的集合
  23.          */
  24.         public static Set<String> quChongFu(Set<String> set) {
  25.                 Set<String> set2 = new TreeSet<String>();
  26.                 Map<Character, Integer> map = null;
  27.                 Iterator<String> it2 = set.iterator();
  28.                 int count;
  29.                 while (it2.hasNext()) {
  30.                         map = new HashMap<Character, Integer>();
  31.                         count = 1;
  32.                         boolean flag = false;
  33.                         String str = it2.next();
  34.                         char[] ch = str.toCharArray();
  35.                         for (int i = 0; i < ch.length; i++) {
  36.                                 if (!map.containsKey(ch[i])) {
  37.                                         count = 1;
  38.                                         map.put(ch[i], count);
  39.                                 }
  40.                                 if (map.containsKey(ch[i])) {
  41.                                         map.put(ch[i], count);
  42.                                         count++;
  43.                                 }
  44.                        
  45.                         }
  46.                 //        System.out.println(map);
  47.                         for(int j=0;j<ch.length;j++){
  48.                                 if(map.get(ch[j])>1){
  49.                                         flag=false;
  50.                                         //System.out.println("r");
  51.                                         break;
  52.                                 }else
  53.                                        
  54.                                 flag=true;
  55.                         }
  56.                         if(flag){
  57.                         //        System.out.println("s");
  58.                                 set2.add(str);
  59.                                
  60.                         }
  61.                 }
  62.                 //System.out.println(set2);
  63.                 return set2;
  64.         }
  65.        
  66.         //利用递归打印所有组合
  67.         /*
  68.          * ch:需要打印在组合的字符数组
  69.          * str:子字符串缓存,每个组合临时保存的变量
  70.          * set:最后存入的集合
  71.          * cout:递归的层数,和ch参数的(长度)相等
  72.          */
  73.         public static void print(char[] ch, StringBuffer str, Set<String> set,
  74.                         int count) {
  75.                 //递归一层自加一次
  76.                 count++;
  77.                 //当递归层数大于字符数组长度时退出
  78.                 if (count > ch.length) {
  79.                         return;
  80.                 }
  81.                 for (int i = 0; i < ch.length; i++) {
  82.                         //当前字符添加到缓存变量中
  83.                         str.append(ch[i]);
  84.                         //打印所有组合,包括重复的
  85.                         System.out.print(str.toString() + ",");
  86.                         //将缓存变量中的数据转换成字符串存入集合中
  87.                         set.add(str.toString());
  88.                         //进入下一层,也就是字符数组的下一个字符
  89.                         print(ch, str, set, count);
  90.                         //删除上次保存的最后一个字符,避免了字符重复
  91.                         str.deleteCharAt(str.length() - 1);
  92.                 }

  93.         }
  94. }
复制代码

作者: 1017161726    时间: 2015-4-2 19:59
好高深的赶脚。。





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2