【问题标题】:returning equation with all possible parenthesis combinations and the result of each返回带有所有可能的括号组合的方程和每个的结果
【发布时间】:2015-11-21 22:01:19
【问题描述】:

在最近的一次采访中,我被要求返回输入字符串上所有可能的操作顺序组合以及结果。您应该返回所有可以用括号“强制”操作的方式/组合。我得到了结果(等式的右侧),但被困在了左侧。我怎么能把左边和右边一起做呢?好像两个问题合二为一……

//input:
console.log(diffWaysToCompute("2 * 3 - 4 * 5"));
//output:
(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10

'use strict'

function getNumbersAndOperators(str) {
  var arr = str.split(" ");
  var operators = [];
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] === "-" || arr[i] === "*" || arr[i] === "+") {
      operators.push(arr[i]);
      arr.splice(i, 1);
      // console.log(operators);
    }
  }
  return [arr, operators];
}
// console.log(getNumbersAndOperators("2 - 1 - 1"))
var diffWaysToCompute = function (input) {
  // var numbers = input.split(" ");
  // console.log(numbers);
  // // console.log(number);
  var results = compute(input);
  results.sort(function (a, b) {
    return a - b;
  });

  //put the numbers length into valid parenthesis:
  var NumbersAndOperators = getNumbersAndOperators(input);
  var numbers = NumbersAndOperators[0];
  console.log(numbers);
  var operators = NumbersAndOperators[1];
  console.log(operators);
  var parens = validParentheses(numbers.length);
  // console.log(numbers);
  console.log(operators);

  // for (var i = 0; i < parens.length; i++) {
  //   for (var j = 0; j < parens[i].length; j++) {
  //       var val = parens[i][j];
  //       console.log(val);
  //     if (val === " ") {
  //       var num = numbers.shift();
  //       parens.splice(val, 0, num);
  //      //starting running into infinite loops and out of time.
  //       j--;
  //     }
  //   }
  //    i--;
  // }
  console.log(parens);
  return results;
};

function validParentheses(n) {
  if (n === 1) {
    return ['( )'];
  }
  var prevParentheses = validParentheses(n - 1);
  var list = {};
  prevParentheses.forEach(function (item) {
    list['( ' + item + ' )'] = null;
    list['( )' + item] = null;
    list[item + '( )'] = null;
  });
  console.log(Object.keys(list))
  return Object.keys(list);
}

function compute(str) {
  var res = [];
  var i;
  var j;
  var k;
  var left;
  var right;
  var string = [];
  var placed = true;

  if (!/[+*-]/.test(str)) { // + - * 
    return [parseInt(str)];
  }
  for (i = 0; i < str.length; i++) {
    if (/\+|\-|\*/.test(str[i])) { // + - * 

      left = compute(str.substring(0, i));
      right = compute(str.substring(i + 1, str.length));
      for (j = 0; j < left.length; j++) {
        for (k = 0; k < right.length; k++) {

          if (str[i] === '+') {
            res.push(parseInt(left[j] + right[k]));
          } else if (str[i] === '-') {
            // string.push("(" + str[i-2], str[i+2] + ")");

            res.push(parseInt(left[j] - right[k]));
          } else if (str[i] === '*') {

            res.push(parseInt(left[j] * right[k]));
          }
        }
      }
    }
  }


  // console.log(string);
  return res;
}


console.log(diffWaysToCompute("2 - 1 - 1"));
console.log(diffWaysToCompute("2 * 3 - 4 * 5"));

【问题讨论】:

  • 只有在运算符不同的情况下才应该加括号?例如1 + 2 + 3 是否应该同时产生 (1+2)+31+(2+3)
  • 不,您应该返回所有可以用括号“强制”操作的方式/组合。
  • 应该1 产生1(1)
  • 我认为任何一种方式都可以
  • 在基本情况下使用括号可能更容易?

标签: javascript algorithm


【解决方案1】:

我从来没有做过这么傻的事情,所以现在让我试试吧。 (一如既往的警告:它高度简化,没有任何制衡!)

解析器是这里最简单的东西:

/*
  Use of strings instead of ASCII codes for legibility.

  I changed x - y to x + (-y) not only for convenience
  but for algebraic correctness, too.

  @param a array number nodes
  @param o array operator nodes

*/
function parse(s,a,o){
  var fnum = 0;
  var uminus = false
  for(var i=0;i<s.length;i++){
    switch(s[i]){
      case '-': uminus = true;
                a.push(fnum);
                o.push('+');
                fnum = 0;
                break;
      case '+':
      case '*':
      case '/': if(uminus){
                  uminus = false;
                  fnum *= -1;
                }
                a.push(fnum);
                o.push(s[i]);
                fnum = 0;
                break;
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9': fnum = fnum * 10 + parseInt(s[i]);
                break;
      default:  break;
    }
  }
  //assuming symmetry
  a.push(fnum);
}

(-一代花了我一些时间,太多时间--我在这里作弊;-)

/* 
   Found in an old notebook (ported from C)
   Algo. is O(n^2) and can be done faster but I
   couldn't be a...ehm, had no time, sorry.

   @idx   int    index into individual result
   @n     int    number of groups
   @open  int    number of opening parentheses
   @close int    number of closing parentheses
   @a     array  individual result
   @all   array  space for all results
*/
function makeParens(idx,n,open,close,a,all){
  if(close == n){
    all.push(a.slice(0));
    return;
  } else {
    if(open > close){
      a[idx] = ')';
      makeParens(idx+1,n,open,close+1,a,all);
    }
    if(open < n){
      a[idx] = '(';
      makeParens(idx+1,n,open+1,close,a,all);
    }
  }
}

现在呢?是的,这花了我一段时间:

/*
   The interesting part
   Not very optimized but working

   @s string the equation
   @return array nicely formatted result
*/
function parenthesing(s){
  var nums = [];
  var ops = [];
  var all = [];
  var parens = [];

  // parse input into numbers and operators
  parse(input,nums,ops);
  /*
    Rules:

    1) out-most parentheses must be open in direction to center
       e.g.:  (1+2+3), 1+(2+3), 1+(2+3)+4
       but not: 1)+(2+3)+(4
       so: first parenthesis on the left side  must be open and
           the last parenthesis on the right side must be close

    2) parentheses in direct neighborhood to a number must be
       open in direction to the number (multiplication is
       not mutual)
       e.g.: 1+(2+3)+4, but not: 1+2(+3+4)

    3) parentheses in direct neighborhood to an operator must be
       closed in direction to the operator (multiplication is
       not mutual)
       e.g.: 1+(2+3)+4, but not: 1+2(+3+)4
  */
  // build combinations separately not in-line
  // it's already a mess, no need to add more
  makeParens(0,nums.length,0,0,[],parens);
  // You may take a look at the raw material here
  // console.log(parens.join("\n"));
  for(var i= 0;i<parens.length;i++){
    var term = [];
    // work on copies to reduce pointer juggling
    var _ops = ops.slice(0);
    var _nums = nums.slice(0);
    for(var j=0;j<parens[i].length;j++){
      if(parens[i][j] === '('){
        term.push("(");
        // rule 3
        if(parens[i][j+1] === ')'){
          term.push(_nums.shift());
        }
        // rules 1,2
        else {
          term.push(_nums.shift());
          term.push(_ops.shift());
        }
      }
      if(parens[i][j] === ')'){
        term.push(")");
        // rules 2,3
        if(parens[i][j+1] !== ')')
          term.push(_ops.shift());
      }
    }
    // some pretty printing
    term = term.join("");
    // eval() because I didn't want to write a parser
    // but if you need one...
    all.push(term + " = " + eval(term));
  }
  return all;
}

我不确定我是否会被那个可憎的人录用。啊,说实话:我怀疑。

但我希望它至少有点帮助。

【讨论】:

    【解决方案2】:

    哎呀。那很棘手。好挑战。我确信这可以减少,但它有效。我使用了 lodash 并分解了各种功能以使其更加灵活。这是一个jsfiddle: https://jsfiddle.net/mckinleymedia/3e8g22Lk/8/

    糟糕 - 必须将 parseInt 添加到添加中,这样它就不会作为字符串添加。

    /*
    //input:
    diffWaysToCompute("2 * 3 - 4 * 5");
    
    //output:
    (2*(3-(4*5))) = -34 - 2,1,0
    ((2*3)-(4*5)) = -14 - 0,2,1 & 2,0,1
    ((2*(3-4))*5) = -10 - 1,0,2
    (2*((3-4)*5)) = -10 - 1,2,0
    (((2*3)-4)*5) =  10 - 0,1,2
    */
    
    'use strict'
    var diffWaysToCompute = function(str) {
      var opsAvailable = ['+','-','/','*'],
          numbers = [],
          operators = [],
          getNumbersAndOperators = function(str) {
              var arr = str.split(" ");
              for (var i in arr) {
                  if ( opsAvailable.indexOf( arr[i] ) > -1 ) {
                      operators.push( arr[i] );
                  } else {
                      numbers.push( arr[i] );
                  }
              };
              return;
          },
          permutator = function(range) {
              var results = [];
              function permute(arr, memo) {
                  var cur, 
                      memo = memo || [];
                  for (var i in arr) {
                      cur = arr.splice(i, 1);
                      if (arr.length === 0) results.push(memo.concat(cur));
                      permute(arr.slice(), memo.concat(cur));
                      arr.splice(i, 0, cur[0]);
                  }
                  return results;
              }
              return permute(_.range(range));
          },
          equations = function( perms ) {
              var results = [];
              _.each(perms, function( perm, k ) {
                  results[k] = nest ( perm );
              });
              return results;
          },
          nest = function( perm ) {
              var eqs = eqs || [],
                  ref = ref || _.range(perm.length).map(function () { return undefined }),
                  eq, 
                  target = undefined;
              for (var i in perm) {
                  var cur = perm[i],
                    next = perm[i] + 1,
                    n1 = numbers[ cur ],
                    n2 = numbers[ next ],
                    r1 = ref[ cur ],
                    r2 = ref[ next ];
                  if ( r1 !== undefined) n1 = eqs [ r1 ];
                  if ( r2 !== undefined) n2 = eqs [ r2 ];
                  var rNew;
                  rNew = eqs.length;
                  for (var x in ref ) {
                      if ( ( ref[ x ] !== undefined ) && ( ref[ x ] == r1 || ref[ x ] == r2 ) ) ref[ x ] = eqs.length;
                  };
                  ref[ cur ] = ref[ next ] = eqs.length;
                  eqs.push({
                      ops: operators[ cur ],
                      nums: [ n1, n2 ]
                  });
              };
    
              return eqs[ eqs.length - 1 ];
          },
          calculations = function ( eqs ) {
              var results = []
              _.each(eqs, function(equation) {
                  results.push(calculate( equation ));
              });
              return results;
          },
          calculate = function( eq ) {
              var result = {
                  text: ""  
              };
              // result.eq = eq;
              result.text += "( ";
              result.total = eq.nums[ 0 ];
              if ( _.isObject(result.total) ) {
                  var result1 = calculate( result.total );
                  result.total = result1.total;
                  result.text += result1.text;
              } else {
                  result.text += eq.nums[ 0 ];
              }
              _.each(eq.ops, function (op, k) {
                  var num = eq.nums[ k + 1 ];
                  result.text += " " + op + " ";
                  if ( _.isObject(num) ) {
                      var result2 = calculate( num );
                      num = result2.total;
                      result.text += result2.text;
                  } else {
                    result.text += num;
                  }
                  if ( op === '+') result.total = parseInt(result.total) + parseInt(num);
                  if ( op === '-') result.total = result.total - num;
                  if ( op === '/') result.total = result.total / num;
                  if ( op === '*') result.total = result.total * num;
              });
              result.text += " )";
              return result;
          },
          display = function( as ) {
              var target = document.getElementById('result');
              target.innerHTML += '<h3 class="problem">String given: ' + str + '</h3>';
              target.innerHTML += '<h4>Permutations</h4>';
              _.each( as, function(a) {
                  target.innerHTML += '<div class="permutation">';
                  target.innerHTML += '  <span class="formula">' + a.text + '</span> = ';
                  target.innerHTML += '  <span class="total">' + a.total + '</span>';
                  target.innerHTML += '</div>';
              });
          },
          perms,
          eqs,
          answers;
    
          getNumbersAndOperators(str);
          perms = permutator( operators.length );
          eqs = equations( perms );
          answers = calculations( eqs );
          answers = _.uniq(answers, 'text');
          display(answers);
      return answers;
    };
    console.log(diffWaysToCompute("2 * 3 - 4 * 5"));
    

    【讨论】:

      猜你喜欢
      • 2018-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 2013-06-17
      • 2021-10-06
      相关资源
      最近更新 更多