非递归地从两个数组生成所有可能的元素排列

时间:2009-05-16 22:02:09

标签: java algorithm

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

请不要递归。 :)

嗯,不,这不是功课。这是一个个人项目,我正在尝试利用遗传算法找到最佳方程来拟合数据。如果您这么认为,对一般算术的描述就足够了。

7 个答案:

答案 0 :(得分:1)

既然你说它不是家庭作业,而且我是一个信任的人......

  1. 通过针对operator array =>运行每个变量来构建一个新的变量 - 运算符组合数组[“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中针对先前构建的阵列运行每个项目,输出并将每个结果存储在新阵列中,然后删除前一个阵列。

  5. 这将扼杀记忆和处理能力,但我无法想到任何更优雅的东西。

    希望它有所帮助。


    这是Ruby codez:

    @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
    

答案 1 :(得分: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 :(得分:0)

既然我也认为这可能是家庭作业,我不会用任何语言给你代码,但是......

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

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

答案 3 :(得分:0)

这不是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]

答案 4 :(得分:0)

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

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]);
        }
    }
}

答案 5 :(得分:0)

  

的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);

答案 6 :(得分:-1)

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