【问题标题】:Mix multiple strings into all the possible combinations将多个字符串混合成所有可能的组合
【发布时间】:2014-11-11 14:52:08
【问题描述】:

我有一些字符串。

  1. 1

  2. 2

  3. 3

如何将它们组合成所有独特的组合?

  1. 123

  2. 132

  3. 213

  4. 231

  5. 312

  6. 321

这是我拥有的代码,但我想在没有 Random 类的情况下工作,因为我知道这不是最好的方法。

import java.util.Random;

public class Solution
{
    public static void main(String[] args)
    {
        String[] names = new String[]{"string1", "string2", "string3"};
        for (int i = 0; i < 9; i++) {
            Random rand = new Random();
            int rand1 = rand.nextInt(3);
            System.out.println(names[rand.nextInt(3)] +
                    names[rand1] +
                    names[rand.nextInt(3)]);
        }
    }
}

【问题讨论】:

  • 你总是要置换 3 个字符串吗?
  • 这种情况下的字符串数为 3,但如果循环更灵活,那就太好了。 @Pier-AlexandreBouchard

标签: java string mixing


【解决方案1】:

您可以通过为每次重复创建另一个嵌套循环来循环数组。

for (String word1 : words) {
    for (String word2 : words) {
        for (String word3 : words) {
            System.out.println(word1 + word2 + word3);
        }
    }
}

以下是如何避免在一个组合中使用相同的单词。

for (String word1 : words) {
    for (String word2 : words) {
        if ( !word1.equals(word2)) {
            for (String word3 : words) {
                if ( !word3.equals(word2) && !word3.equals(word1)) {
                    System.out.println(word1 + word2 + word3);
                }
            }
        }
    }
}

这是一个可以有多种长度的类版本,使用回溯。

import java.util.ArrayList;
import java.util.List;


public class PrintAllCombinations {

    public void printAllCombinations() {
        for (String combination : allCombinations(new String[] { "A", "B", "C" })) {
            System.out.println(combination);
        }
    }

    private List<String> allCombinations(final String[] values) {
        return allCombinationsRecursive(values, 0, values.length - 1);
    }

    private List<String> allCombinationsRecursive(String[] values, final int i, final int n) {
        List<String> result = new ArrayList<String>();
        if (i == n) {
            StringBuilder combinedString = new StringBuilder();
            for (String value : values) {
                combinedString.append(value);
            }
            result.add(combinedString.toString());
        }
        for (int j = i; j <= n; j++) {
            values = swap(values, i, j);
            result.addAll(allCombinationsRecursive(values, i + 1, n));
            values = swap(values, i, j); // backtrack
        }
        return result;
    }

    private String[] swap(final String[] values, final int i, final int j) {
        String tmp = values[i];
        values[i] = values[j];
        values[j] = tmp;
        return values;
    }

}

请注意,使用随机方法,不能保证所有组合都被获取。因此,它应该始终遍历所有值。

【讨论】:

  • 是我,还是name1和name3可以相等?
  • 很好的解决方案,如果有更多的 3 个字符串,您能否解释一下是否还有其他选项。 @JordiBetting
  • 我添加了适用于所有长度数组的代码。
【解决方案2】:

您可以使用Google Guava 库来获取所有字符串排列。

    Collection<List<String>> permutations = Collections2.permutations(Lists.newArrayList("string1", "string2", "string3"));
    for (List<String> permutation : permutations) {
        String permutationString = Joiner.on("").join(permutation);
        System.out.println(permutationString);
    }

输出:

string1string2string3
string1string3string2
string3string1string2
string3string2string1
string2string3string1
string2string1string3

【讨论】:

    【解决方案3】:

    首先,您所追求的结果中没有任何随机性 - 并且Random.nextInt() 不会给您唯一的排列,或者不一定是所有排列。

    对于 N 元素,有 N!N-阶乘)唯一序列 - 我相信这就是您所追求的。因此,您的三个元素给出了六个独特的序列 (3! = 3 * 2 * 1)。

    这是因为您可以选择三个元素作为第一个位置 (N),然后选择两个剩余元素作为第二个位置 (N-1),剩下一个未选择的元素作为最后一个位置 ( N-2)。

    因此,这意味着您应该能够迭代序列的所有排列;以下代码应该对 3 个元素的序列执行此操作:

    // Select element for first position in sequence...
    for (int i = 0 ; i < 3 ; ++i)
    {
        // Select element for second position in sequence...
        for (int j = 0 ; j < 3 ; ++j)
        {
            // step over indices already used - which means we
            // must test the boundary condition again...
            if (j >= i) ++j;
            if (j >= 3) continue;
    
            // Select element for third position in sequence...
            // (there is only one choice!)
            for (int k = 0 ; k < 3 ; ++k)
            {
                // step over indices already used, recheck boundary
                // condition...
                if (k >= i) ++k;
                if (k >= j) ++k;
                if (k >= 3) continue;
    
                // Finally, i,j,k should be the next unique permutation...
                doSomethingWith (i, j, k);
            }
        }
    }
    

    现在,我刚刚写了这个 OTH,所以没有任何保证。但是,希望你能看到你需要做什么。当然,这可以并且应该推广到支持任意集合大小,在这种情况下,您可以使用序列的索引填充 int[]

    但是,我想如果你环顾四周,将会有一些更好的算法来生成序列的排列。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-06
      • 1970-01-01
      • 2017-11-11
      • 1970-01-01
      • 2012-08-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多