【问题标题】:Nonrecursively generating all possible permutations of elements from two arrays非递归地从两个数组中生成所有可能的元素排列
【发布时间】:2009-05-16 22:02:09
【问题描述】:

我正在尝试生成所有可能的方程式,给定一个字符串运算符数组(+、-、*、/)和一个变量字符串数组(a、b、c ...)。每个方程将由成对的变量和数字 (a+ b- c/ b) 组成,除了最后一个变量,它后面没有运算符。该算法必须生成可变长度的方程(2 项、6 项等)。在 Java 中生成此列表的最有效方法是什么?

请不要递归执行。 :)

嗯,不,这不是家庭作业。这是一个个人项目,我试图利用遗传算法找到适合数据的最佳方程。如果您相信的话,笼统地描述算法就足够了。

【问题讨论】:

  • 曾经有一个 plz-email-me-teh-codez 标签,但我找不到。你真的对最有效的方法感兴趣还是只对any 方法感兴趣? ;)
  • 您能否详细说明无递归要求?递归似乎是自然的方式......
  • 我们可以使用递归。这是自然的方式。但是当数组很大时,您需要做的递归量可能会超过堆栈。此外,递归会引入额外的开销并影响性能。
  • 这个需要写自修改程序集,我只有PPC版本。除非你在 PPC 上?
  • 为什么我们需要编写自修改程序集?

标签: java algorithm


【解决方案1】:

所以这是我想出的代码。我使用单个 LinkedList 来存储我生成的方程。我生成所有可能的运算符和变量对,然后将它们附加到我已经生成的解决方案中以提出新的解决方案。有没有更好/更快的方法来做到这一点?

LinkedList<String> solutions = new LinkedList<String>();
//String[] vars and operators are initialized elsewhere.
int start = 0, end = solutions.size()-1;

//creating the first solutions
for(String s : vars)
    solutions.add(s);


//precompute pairs of operators and variables
String[] pairs = new String[operators.length * vars.length];
for(int i=0, j=0; j<operators.length; j++)
for(int k=0; k<vars.length; k++)
{
    pairs[i++]= operators[j]+vars[k];
}

//while the the terms in equations is under maximum
while(solutions.get(solutions.size()-1).split("[+/*-]").length<4)
{
    for(int i=start; i<end; i++)
    {
        String soln = solutions.get(i);
        for(int j=0; j<pairs.length; j++)
        {
            solutions.add(soln+pairs[j]);
        } 
    }
    start = end +1;
    end = solutions.size()-1;
}

【讨论】:

    【解决方案2】:

    既然你说这不是功课,我是个值得信赖的人……

    1. 通过针对运算符数组运行每个变量来构建一个新的变量运算符组合数组 => ["a+", "a-", "a*", "a/", "b+" .. . "d/"]。我们称它为 BuiltArray1

    2. 针对运算符运行此数组,输出每个运算符并将每个运算符存储在一个新数组中 => ["a+a", "a+b", "a+c", "a+d", “a-a” ...“d/d”]。我们称它为 BuiltArray2。如果我们愿意的话,我们现在可以删除原来的变量数组 ["a, "b", "c", "d"] - 我们不会再使用它了。

    3. 现在事情变得更有趣了...现在我们正在构建 BuiltArray3。对 BuiltArray2 中的每一项运行 BuiltArray1 中的每一项,输出每一项并将每一项存储在 BuiltArray3 => ["a+a+a", "a-a+a", "a*a+a", "a/a+ a"、"b+a+a" ... "d/d/d"]。我们现在可以删除 BuiltArray2 以节省一些内存(这将开始快速消耗内存!)

    4. 对于BuiltArray4,直到我们的计算机在它可以处理的最后一个BuiltArray_n 上尖叫而死之前,我们针对先前构建的数组运行BuiltArray1 中的每个项目,输出并将每个结果存储在一个新数组中,然后删除之前的数组。

    这会消耗内存和处理能力,但我想不出任何更优雅的东西。

    希望对你有帮助。


    这是 Ruby 代码:

    @arr1 = ["a", "b", "c", "d"]
    arr2 = ["+", "-", "*", "/"]
    @base = []
    @arr1.each do |char|
      arr2.each do |op|
        @base << char + op
      end
    end
    @right_vals = @arr1
    loop do
      @new_values = []
      @base.each do |left|
        @right_vals.each do |right|
          val = left + right
          puts val
          @new_values << val
        end
      end
      @right_vals = @new_values
    end
    

    【讨论】:

    • 我刚刚完成了与您提出的非常相似的实现。但是,相反,我只是将所有内容存储在一个 LinkedList 而不是多个数组中。我使用了以前生成的解决方案,并添加了一个运算符和一个变量来获得新的解决方案,并将其添加到列表中。它确实需要大量的内存和时间,但它确实有效。我很感激你不是一个怪人,并相信这不是家庭作业。稍后我会发布代码。
    • 此解决方案的好处是您可以在一个无限或有界循环中实现这一点,将旧的两个数组换成新的两个数组,然后进行组合 - 它使编码变得简短。删除未使用的内存也总是很好,尤其是像这样的无限问题,你需要每一点都走得更远。
    【解决方案3】:

    因为我也认为这可能是家庭作业,所以我不会给你任何语言的代码,但是......

    你可以有两个嵌套循环,一个循环遍历数组一,另一个循环遍历数组二。

    您会看到每个组合的索引都将通过内部循环,您可以在那里进行数学运算。

    【讨论】:

    • 拘留!我整天潜伏在这些新奇的网络事物上,只等作弊!
    【解决方案4】:

    这不是在 Java 中,它是递归的,但有趣的是,Haskell 解决方案看起来像这样:

    permuteEquations :: Int -> [String] -> [String] -> [String]
    permuteEquations 1 vars _ = vars
    permuteEquations n vars ops = 
        [v ++ t1 | t1 <- [o ++ t2 | t2 <- permuteEquations (n-1) vars ops, o <- ops],
                   v  <- vars]
    

    这会生成包含 n 个变量的所有可能的方程。

    或者,如果您想要一个以一个变量(即变量列表)的方程开始,然后一直到 n 个变量的版本,那么它是:

    permuteEquations1 :: Int -> [String] -> [String] -> [String]
    permuteEquations1 0 _ _ = []
    permuteEquations1 n vars ops = 
        [v ++ t1 | t1 <- "" : [o ++ t2 | t2 <- permuteEquations1 (n-1) vars ops, 
                                         o  <- ops], 
                   v  <- vars]
    

    由于惰性求值,这些函数在恒定空间中运行,如果您要生成数十亿个方程,这将非常方便。有谁知道你会如何在Java中做到这一点? (我确信它是可能的,我只是想看看它是什么样子的)。

    实际上,由于惰性评估,您可以摆脱 n 术语并生成一个无限列表,客户端可以将其截断为所需的任何长度。

    permuteEquations2 :: [String] -> [String] -> [String]
    permuteEquations2 vars ops = 
        [v ++ t1 | t1 <- "" : [o ++ t2 | t2 <- permuteEquations2 vars ops, o <- ops], 
                   v  <- vars]
    

    【讨论】:

      【解决方案5】:

      运行时间随着变量的数量呈指数增长。这是另一种方法。

      import java.util.List;
      import java.util.ArrayList;
      
      public class Equations {
          public static void main(String[] args) {
              String[] operators = "+ - * / %".split(" ");
              String[] variables = "a b c d e f g".split(" ");
              printAllPermutations(operators, variables);
          }
      
          private static void printAllPermutations(String[] operators, String[] variables) {
              if (variables.length >= 31)
                  throw new IllegalArgumentException("Need to use BigInteger to support such a large number variables.length="+variables.length);
      
              int permuations = 1 << variables.length;
              for(int p=1;p<permuations;p++) {
                  List<String> variableList = new ArrayList<String>();
                  int p2 = p;
                  for (String variable : variables) {
                      if ((p2 & 1) != 0)
                          variableList.add(variable);
                      p2 /= 2;
                  }
                  printPermutations(operators, variableList.toArray(new String[variableList.size()]));
              }
          }
      
          private static void printPermutations(String[] operators, String[] variables) {
              long permutations = 1;
              // more accurate than Math.pow.
              for (int i = 0; i < variables.length-1; i++) {
                  String variable = variables[i];
                  permutations *= operators.length;
              }
              for(long p = 0; p < permutations;p++) {
                  long p2  = p;
                  for (int i = 0; i < variables.length-1; i++) {
                      System.out.print(variables[i]);
                      int oper = (int) (p2 % operators.length);
                      System.out.print(operators[oper]);
                      p2 /= operators.length;
                  }
                  System.out.println(variables[variables.length-1]);
              }
          }
      }
      

      【讨论】:

        【解决方案6】:

        Javascript 给集合,第一个用于操作数,应应用于第二个数字集合,然后我们用目标值评估生成的表达式。

        var targetValue=10;
        var set=[2,4,8,16,64];
        //var ops=['+','-', '/', '*'];
        
        var retArray=new Array();
        
        function permutateSigns(operand, numbers, pos, epx){
        
                var sum = 0;
                if (pos == numbers.length-1) {
                    epx += numbers[pos];
                    //console.log(epx);
                    retArray.push(epx);
                } else {
                    epx += (numbers[pos]) + operand;
                    permutateSigns('+', numbers, pos + 1, epx);
                    permutateSigns('-', numbers, pos + 1, epx);
                    permutateSigns('*', numbers, pos + 1, epx);
                    permutateSigns('/', numbers, pos + 1, epx);
                }
            }
        permutateSigns('+',set,0,"");
        var per=retArray;
        console.log(per);
        
        var validExpr;
        for (var i = 0; i < retArray.length; i++) {
            var result=eval(retArray[i]);
        
            if(result===targetValue)
                validExpr= retArray[i];
            else
             console.log(retArray[i] + ":" + eval(retArray[i]));
        }
        console.log("valid expression is:" + validExpr + "; value:"+ eval(validExpr) + "number of permutations is:"+ retArray.length);
        

        【讨论】:

          【解决方案7】:

          我认为这与语言无关。这是作业吗?这听起来像是功课,所以我不会给你举个例子,但我会使用 3 个while 循环(虽然你可以很容易地使用for 循环,我只是更喜欢使用whiles)。

          【讨论】:

          • 闻起来非常像家庭作业。忍不住为这个问题添加了作业标签:)
          猜你喜欢
          • 1970-01-01
          • 2014-09-07
          • 2012-05-05
          • 2018-05-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多