得到数学表达式的每个排列

时间:2015-04-28 12:12:51

标签: java algorithm recursion permutation dynamic-programming

任务

给出一个数字列表

例如:

1,2,3。

使用乘法或加法(* / +)

的操作获取这些数字的每个组合

所以在上面的例子中,组合将是

1 + 2 + 3

1 + 2 * 3

1 * 2 * 3

1 * 2 + 3

我写了一个基本的递归方法来解决它,我想到的方式如下

鉴于一个数字,我可以

  1. 添加下一个号码

  2. 乘以下一个数字

  3. 因此你会得到一棵这样的树

               START NUMBER
                  /   \
                 *     +
                / \   /  \
               *   + *    +
    

    等等...

    但输出每次输出两次输出

    使用1,2,3时得到的输出是

    1 * 2 + 3

    1 * 2 + 3

    1 * 2 * 3

    1 * 2 * 3

    1 + 2 + 3

    1 + 2 + 3

    1 + 2 * 3

    1 + 2 * 3

    我的问题

    1. 这是一个可以接受的算法,如果是这样,我的代码出了什么问题

    2. 还有另一种更有效的方法吗?

    3. CODE

          package AG;
      
      import java.util.LinkedList;
      import java.util.Stack;
      
      /**
       *
       * @author Tamir Shklaz
       */
      public class ArithmeticGame {
      
          /**
           * @param args the command line arguments
           */
          public static void main(String[] args) {
              LinkedList<Integer> numbers = new LinkedList<>();
              LinkedList<Integer> number = new LinkedList<>();
              for (int i = 1; i <= 3; i++) {
                  numbers.add(i);
              }
              permutateSigns('*', numbers, 0, "");
              permutateSigns('+', numbers, 0, "");
      
          }
      
      
          public static void permutateSigns(char operation, LinkedList<Integer> number, int pos, String expresion) {
              double sum = 0;
              if (pos == number.size()-1) {
                  expresion += number.get(pos);
                  System.out.println(expresion);
      
      
              } else {
                  expresion += (Integer.toString(number.get(pos)) + Character.toString(operation));
                  permutateSigns('+', number, pos + 1, expresion);
                  permutateSigns('*', number, pos + 1, expresion);
              }
      
          }
      }
      

6 个答案:

答案 0 :(得分:2)

你的错误是当你最后一次调用permutateSigns()函数两次增加位置时,所以每个组合的'post == number.get(pos)'都是两次。有一次,下面的标志是+和第二次*。如果操作char为'+'(例如

),则非常快速的解决方法是仅输出解决方案
if(operation=='+')
  System.out.println(expression);

对于更优雅的解决方案,您可能需要重新安排操作/更改算法流程。

在这里,我将算法更改为首先输入运算符,然后输入数字

 public static void main(String[] args) {
        LinkedList<Integer> numbers = new LinkedList<>();
        LinkedList<Integer> number = new LinkedList<>();
        for (int i = 1; i <= 3; i++) {
            numbers.add(i);
         }
        permutateSigns('*', numbers, 1, numbers.get(0).toString());
        permutateSigns('+', numbers, 1, numbers.get(0).toString());
    }

    public static void permutateSigns(char operation, LinkedList<Integer> number, int pos, String expression) {
        if (pos == number.size()-1) {
            expression = expression + operation + number.get(pos);
            System.out.println(expression);
        } else {
            expression += ( Character.toString(operation) + Integer.toString(number.get(pos)));
            permutateSigns('+', number, pos + 1, expression);
            permutateSigns('*', number, pos + 1, expression);
        }

    }
}

答案 1 :(得分:2)

我认为你的错误是你将一个操作符传递给permutateSigns函数而不是给所有操作符。

因此,您在开头两次调用相同的函数,这会导致答案加倍。

这是更正的代码(我认为这是你需要的)

public class ArithmeticGame {

    public static void main(String[] args) {
        LinkedList<Integer> numbers = new LinkedList<>();
        for (int i = 1; i <= 3; i++) {
            numbers.add(i);
        }
        char[] operations = { '*', '+' };
        permutateSigns(operations, numbers, 0, "");
    }

    public static void permutateSigns(char[] operations, LinkedList<Integer> numbers, int pos, String expression) {
        expression += numbers.get(pos);
        if (pos == numbers.size() - 1) {
            System.out.println(expression);
        } else {
            for (char operation : operations) {
                permutateSigns(operations, numbers, pos + 1, expression + operation);
            }
        }
    }
}

此外,我建议您使用 ArrayList 而不是 LinkedList ,因为获取执行的操作将具有 O( 1)时间而不是 O(n)

答案 2 :(得分:1)

有一种更好的解决方案。你的代码是递归的,并且由于这个原因会有一个可怕的运行时。会有一个更简单的解决方案:如果您要添加n个运算符和m个数字,则总共有n ^ (m - 1)个可能的组合。通过将每个运算符编码为数字,您可以创建基于n的数字。或者相反:(0 , n ^ (m - 1)中的每个数字都可以解析为运算符的组合。

public static void main(String[] args){
    int[] numbers = {1 , 2 , 3};
    String[] operators = {"+" , "*"};

    int maxEnc = 1;
    for(int i = 0 ; i < numbers.length - 1 ; i++)
        maxEnc *= operators.length;

    int[] digits = new int[operators.length];
    int tmp;
    for(int i = 0 ; i < maxEnc ; i++){
        tmp = i;

        //interprete tmp as a n-based number and retrieve it's digits
        for(int j = 0 ; j < operators.length ; j++){
            digits[j] = tmp % operators.length;
            tmp /= operators.length;
        }

        String result = "";
        for(int j = 0 ; j < numbers.length - 1 ; j++)
            //reinterpret the digits as operators
            result += numbers[j] + operators[digits[j]];
        result += numbers[numbers.length - 1];

        System.out.println(result);
    }
}

注意:此代码也可以运行更多运算符或更多数字

答案 3 :(得分:0)

显然我的回答有点迟了。问题是你没有经常在操作数上迭代。这是解决您问题的清晰代码。

public class Test {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        for (int i = 1; i <= 3; i++) {
            numbers.add(i);
        }
        permutateSigns(' ', numbers, 0, "");
    }

    public static void permutateSigns(char operation, List<Integer> number, int pos, String expresion) {
        expresion += number.get(pos);
        if (pos == number.size() - 1) {
            System.out.println(expresion);
        } else {
            for (Operands operand : Operands.values()) {
                permutateSigns(operand.getValue(), number, pos + 1, expresion + operand.getValue());
            }
        }
    }

    public enum Operands {

        ADD('+'), MULTIPLY('*');
        private final char operand;

        private Operands(char operand) {
            this.operand = operand;
        }

        public char getValue() {
            return operand;
        }
    }
}

答案 4 :(得分:0)

+----+-------+------+-------+------+
|    |       |      |       |      |
| 1  |   op1 | 2    |  op2  |  3   |
+----------------------------------+
|    |       |      |       |      |
|    |       |      |       |      |
+----------------------------------+
|    |       |      |       |      |
|    |       |      |       |      |
|    |       |      |       |      |
|    |       |      |       |      |
|    |       |      |       |      |
|    |       |      |       |      |
+----+-------+------+-------+------+

你可以看到这个问题。 基本上,您只需要生成需要使用的运算符的排列。在这种情况下,他们ad +和* 因此,它们的排列是: + + + * * + * * 然后你只需要将它们插入我在图中显示的操作员位置。 留下编码部分。

:)

答案 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);