【问题标题】:Algorithm to generate all combinations of a string生成字符串的所有组合的算法
【发布时间】:2012-02-16 11:10:30
【问题描述】:

我在网上找到了一个链接,该链接显示了一种生成字符串所有组合的算法:http://www.mytechinterviews.com/combinations-of-a-string

算法复制如下。

void combine(String instr, StringBuffer outstr, int index)
{
    for (int i = index; i < instr.length(); i++)
    {
        outstr.append(instr.charAt(i));
        System.out.println(outstr);
        combine(instr, outstr, i + 1);
        outstr.deleteCharAt(outstr.length() - 1);
    }
} 

combine("abc", new StringBuffer(), 0);

我不明白的是这条线:

outstr.deleteCharAt(outstr.length() - 1);

如果我删除这一行,程序显然不再工作了,但为什么首先需要这样做呢?我理解递归的想法,我们改变初始字符并递归剩余的字符,但 deleteChar 行似乎在逻辑上不适合任何地方。添加 outstr.deleteCharAt 行的原因是什么?

【问题讨论】:

  • 由于我们想要所有组合,有charAt(i) 没有它,我们需要将这两种情况分开。那些没有 charAt(i) 的组合在 for 循环的下一次迭代中被处理,在当前迭代结束之前通过 deleteCharAt() 的魔力。

标签: java algorithm combinations


【解决方案1】:

计算可能的字符串组合的最简单方法在这里 ...

在给定批次 N = NcR 中找到 R 个组合

所以我们在这里发现的是,所有可能的组合 = Nc0 + Nc1 .... + Ncn = 2 Pow N

因此,对于长度为 N 个字符的给定单词,您将获得 2 个 Pow N 组合。

如果你用二进制表示 1 到 (2 Pow N) 个整数,并将你的 char 放在 1 存在的地方,最后你会得到解决方案。

示例:

输入:ABC

解决方案:

ABC 长度为 3。所以可能的组合 2 Pow 3 = 8

如果 0 - 8 用二进制表示

000 =

001 = C

010 = B

011 = 公元前

100 = 一个

101 = 交流

110 = AB

111 = ABC

所有可能的组合如上所示。

【讨论】:

  • 谢谢!这样可以更轻松地理解解决方案。
  • 太棒了!我相信这是最直观的实现方式
  • 它没有 BA, CA, CBA .. 和其他的,我猜这些是可能的,不同的字符串。
【解决方案2】:

outstr.deleteCharAt 的调用通过删除outstr 的最后一个字符来抵消outstr.append 的影响。

每次循环迭代如下:

  1. 附加一个字符
  2. 打印结果
  3. i+1级别执行递归调用
  4. 删除我们在步骤 1 中添加的字符

【讨论】:

    【解决方案3】:

    它平衡了循环体的第一行,将 outstr 恢复到循环体顶部的位置(通过从附加的 instr 中删除字符)。

    【讨论】:

      【解决方案4】:

      它非常合乎逻辑。你看我们这里有一个递归算法。在位置i 的每个步骤中,我们放置字符串的一个字母,然后递归调用该函数以在下一个位置放置另一个字母。但是,当我们从递归返回时,我们需要删除我们最初放置的字符,以便我们可以将其替换为序列中下一个可能的字符。示例:

      append a on pos 0 -> a
      call recursion
      append a on pos 1 -> aa
      call recursion
      append a on pos 2 -> aaa
      return from recursion
      remove a from pos 2 -> aa
      append b on pos 2 -> aab
      return from recursion
      remove b from pos 2 -> aa
      append c on pos 2 -> aac
      etc.
      

      【讨论】:

        【解决方案5】:

        下面的代码是生成字符串的排列组合,基本概念是一次选择一个字符:

        public class permutecombo
        {
          static void initiate(String s)
          {
            permute("", s);
            System.out.println("----------------------------------------- ");
            combo("", s);
            System.out.println("----------------------------------------- ");
          }
        
          static void combo(String prefix, String s)
          {
            int N = s.length();
        
            System.out.println(prefix);
        
            for (int i = 0 ; i < N ; i++)
              combo(prefix + s.charAt(i), s.substring(i+1));
          }
          static void permute(String prefix, String s)
          {
            int N = s.length();
        
            if (N == 0)
              System.out.println(" " + prefix);
        
            for (int i = 0 ; i < N ; i++)
              permute(prefix + s.charAt(i), s.substring(0, i) + s.substring(i+1, N));
          }
        
          public static void main(String[] args)
          {
            String s = "1234";
            initiate(s);
          }
        }
        

        【讨论】:

          【解决方案6】:

          我们可以使用前面提到的位概念来生成一个字符串的所有子字符串。这是执行此操作的代码(在 C++ 中,但您明白了):-

          string s;
          int n = s.size();
          int num = 1<<n;
          for(int i =1; i< num ; i++){ //Checks all the permutations.
              int value = i;
              int j, pos;
              for (j=1, pos=1; j < num; j<<=1, pos++) //Finds the bits that are set
                  if (i & j)
                      cout<<s[pos-1]; //You can print s[n-pos] to print according to bit position
              cout<<endl;        
          }
          

          例如;- 字符串 s = abc ,

           The size is 3  . So we check from 1 to 7 ( 1<<3).
           for i = 1 ( 001 ) , the first bit is set, so a is printed.
           for i = 2 ( 010 ) , the second bit is set, so b is printed.
           for i = 3 ( 011 ) , the first and second bit are set, so ab is printed.
           .
           .
           .
           for i = 7 ( 111 ) , all three bits are set, so abc is printed.
          

          【讨论】:

            【解决方案7】:

            这是没有 OP 问题中棘手的回溯步骤的 C++ 代码。

            #include <iostream>
            #include <string>
            using namespace std;
            static const string in("abc");
            void combine(int i, string out)
            {
                if (i==in.size()) {
                    cout << out << endl;
                    return;
                }
                combine(i+1, out);
                combine(i+1, out+in[i]);
            }
            
            int main()
            {
                combine(0, "");
                return 0;
            }
            

            我希望这能更好地体现组合的精神。

            【讨论】:

              【解决方案8】:
              outstr.deleteCharAt(outstr.length() - 1); 
              

              表示你有

              n^(n-1)/2 pairs of combinations.
              

              迭代的for循环在递归函数调用后不会停止,所以你需要删除输出缓冲区中的最后一个字符,因为你不想得到

              n^n/2 pairs of combinations.
              

              在图论中,这将是短路。

              【讨论】:

                【解决方案9】:
                // IF YOU NEED REPEATITION USE ARRAYLIST INSTEAD OF SET!!
                
                import java.util.*;
                public class Permutation {
                
                    public static void main(String[] args) {
                        Scanner in=new Scanner(System.in);
                        System.out.println("ENTER A STRING");
                        Set<String> se=find(in.nextLine());
                        System.out.println((se));
                    }
                    public static Set<String> find(String s)
                    {
                        Set<String> ss=new HashSet<String>();
                        if(s==null)
                        {
                            return null;
                        }
                        if(s.length()==0)
                        {
                            ss.add("");
                        }
                        else
                        {
                            char c=s.charAt(0);
                            String st=s.substring(1);
                            Set<String> qq=find(st);
                            for(String str:qq)
                            {
                                for(int i=0;i<=str.length();i++)
                                {
                                    ss.add(comb(str,c,i));
                                }
                            }
                        }
                        return ss;
                
                    }
                    public static String comb(String s,char c,int i)
                    {
                        String start=s.substring(0,i);
                        String end=s.substring(i);
                        return start+c+end;
                    }
                
                }
                
                
                // IF YOU NEED REPEATITION USE ARRAYLIST INSTEAD OF SET!!
                

                【讨论】:

                  【解决方案10】:
                  import com.google.common.collect.Lists;
                  
                  import java.util.List;
                  
                  public class Combinations {
                      public static String[] getCombinations(final String input) {
                          final List<String> combinations = Lists.newArrayList();
                          getCombinations(input.toCharArray(), combinations, 0, "");
                          return combinations.toArray(new String[0]);
                      }
                  
                      private static void getCombinations(final char[] input, final List<String> combinations, final int index, final String combination) {
                          if (index == input.length) {
                              combinations.add(combination);
                              return;
                          }
                          getCombinations(input, combinations, index + 1, combination + String.valueOf(input[index]));
                          getCombinations(input, combinations, index + 1, combination);
                      }
                  
                  }
                  

                  相应的测试:

                  import org.hamcrest.Matchers;
                  import org.junit.Test;
                  
                  import static org.hamcrest.MatcherAssert.assertThat;
                  
                  public class CombinationsTest {
                      @Test
                      public void testCombinations() {
                          verify(Combinations.getCombinations(""), "");
                          verify(Combinations.getCombinations("a"), "a", "");
                          verify(Combinations.getCombinations("ab"), "ab", "a", "b", "");
                          verify(Combinations.getCombinations("abc"), "abc", "ab", "ac", "a", "bc", "b", "c", "");
                          verify(Combinations.getCombinations("abcd"),
                                  "abcd", "abc", "abd", "ab", "acd", "ac", "ad", "a", "bcd", "bc", "bd", "b", "cd", "c", "d", "");
                      }
                  
                      private void verify(final String[] actual, final String... expected) {
                          assertThat(actual, Matchers.equalTo(expected));
                      }
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2020-08-18
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-05-17
                    • 1970-01-01
                    • 2013-12-23
                    • 2012-08-23
                    相关资源
                    最近更新 更多