Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 从算术表达式中删除多余的括号_Algorithm_Data Structures_Stack_Permutation - Fatal编程技术网

Algorithm 从算术表达式中删除多余的括号

Algorithm 从算术表达式中删除多余的括号,algorithm,data-structures,stack,permutation,Algorithm,Data Structures,Stack,Permutation,这是一个面试问题,对于这个问题,我在stackoverflow或外界都没有找到令人满意的答案。问题陈述: 给定一个算术表达式,删除多余的括号。例如。 ((a*b)+c)应该变成a*b+c 我可以想出一种明显的方法将中缀表达式转换为后缀并将其转换回中缀-但有更好的方法吗?当且仅当括号中包含一个形式为X%X%…%的未加密表达式时,才需要一对括号X,其中X为括号内表达式或原子,%为二元运算符,且至少有一个运算符%的优先级低于直接附加到括号内表达式任一侧的运算符;或者如果这是整个表达。例如在 q * (

这是一个面试问题,对于这个问题,我在stackoverflow或外界都没有找到令人满意的答案。问题陈述:

给定一个算术表达式,删除多余的括号。例如。 ((a*b)+c)应该变成a*b+c


我可以想出一种明显的方法将中缀表达式转换为后缀并将其转换回中缀-但有更好的方法吗?

当且仅当括号中包含一个形式为X%X%…%的未加密表达式时,才需要一对括号X,其中X为括号内表达式或原子,%为二元运算符,且至少有一个运算符%的优先级低于直接附加到括号内表达式任一侧的运算符;或者如果这是整个表达。例如在

q * (a * b * c * d) + c
周围的运算符是{+,*},括号内的最低优先级运算符是*,因此不需要括号。另一方面,在

q * (a * b + c * d) + c
括号内的优先级运算符+低于周围的运算符*,因此它们是必需的。然而,在

z * q + (a * b + c * d) + c
括号不是必需的,因为外部*未附加到括号中的表达式

之所以如此,是因为如果表达式(X%X%…%X)中的所有运算符的优先级高于周围的运算符,那么即使删除括号,也会首先计算出内部运算符

因此,您可以通过此算法直接检查任何一对匹配括号的冗余:

Let L be operator immediately left of the left parenthesis, or nil
Let R be operator immediately right of the right parenthesis, or nil
If L is nil and R is nil:
  Redundant
Else:
  Scan the unparenthesized operators between the parentheses
  Let X be the lowest priority operator
  If X has lower priority than L or R:
    Not redundant
  Else:
    Redundant
您可以对此进行迭代,删除冗余对,直到所有剩余对都是非冗余的

例如:

((a * b) + c * (e + f))
(从左到右处理对):

最终结果:

a * b + c * (e + f)

我刚刚想出了一个答案:

该处所为:

1. the expression has been tokenized
2. no syntax error
3. there are only binary operators
输入:

list of the tokens, for example:
   (, (, a, *, b, ), +, c, )
输出:

set of the redundant parentheses pairs (the orders of the pairs are not important),
for example,
   0, 8
   1, 5
请注意:集合不是唯一的,例如,((a+b))*c,我们可以删除外圆括号或内圆括号,但最终表达式是唯一的

数据结构:

a stack, each item records information in each parenthese pair
the struct is:
   left_pa: records the position of the left parenthese
   min_op: records the operator in the parentheses with minimum priority
   left_op: records current operator
算法

1.push one empty item in the stack
2.scan the token list
    2.1 if the token is operand, ignore
    2.2 if the token is operator, records the operator in the left_op, 
        if min_op is nil, set the min_op = this operator, if the min_op 
        is not nil, compare the min_op with this operator, set min_op as 
        one of the two operators with less priority
    2.3 if the token is left parenthese, push one item in the stack, 
        with left_pa = position of the parenthese
    2.4 if the token is right parenthese, 
        2.4.1 we have the pair of the parentheses(left_pa and the 
             right parenthese)
        2.4.2 pop the item
        2.4.3 pre-read next token, if it is an operator, set it 
             as right operator
        2.4.4 compare min_op of the item with left_op and right operator
             (if any of them exists), we can easily get to know if the pair 
             of the parentheses is redundant, and output it(if the min_op
             < any of left_op and right operator, the parentheses are necessary,
             if min_op = left_op, the parentheses are necessary, otherwise
             redundant) 
        2.4.5 if there is no left_op and no right operator(which also means 
             min_op = nil) and the stack is not empty, set the min_op of top 
             item as the min_op of the popped-up item
扫描到b后,我们得到堆栈:

index left_pa min_op left_op
0
1     0       
2     1       *      *       <-stack top
和预读运算符“+”,因为最小运算优先级“*”>“+”,所以对(1,5)是冗余的,所以输出它。 然后扫描到最后一个“'),现在我们有了堆栈

index left_pa min_op left_op
0
1     0       +      + 
我们弹出此项(因为我们在位置8处遇到“')),并预读下一个运算符,因为没有运算符,在索引0处,没有左_op,所以输出该对(0,8)

例二

a*(b+c)
当我们遇到“')”时,堆栈如下所示:

index  left_pa  min_op left_op
0               *      *
1      2        +      +

现在,我们在索引=1处弹出该项,比较索引0处的min_op“+”和左侧_op“*”,我们可以发现“(”,“)”是必需的

如果表达式有效,该解决方案有效。我们需要将运算符映射到优先级值

a。从数组的两端遍历以找出两端匹配的括号。 设索引分别为i和j

b。现在从i遍历到j,找出没有包含在任何括号内的最低优先级运算符

c。将此运算符的优先级与左括号和右括号中的运算符进行比较。如果不存在此类运算符,则将其优先级视为-1。如果运算符的优先级高于这两个,请删除i和j处的括号

d。继续执行步骤a到c,直到i
  • 在堆栈中推送一个空项
  • 扫描令牌列表

    2.1如果标记是操作数,则忽略

    2.2如果令牌是操作员,则在左_op中记录操作员, 如果min_op为nil,如果min_op 不为零,将最小值与此运算符进行比较,将最小值设置为 优先级较低的两个操作员之一

    2.3如果标记是左括号,则在堆栈中推送一项, 带左_pa=括号的位置

    2.4如果令牌是右括号:

    2.4.1我们有一对括号(左括号和右括号) 右括号)

    2.4.2弹出项目

    2.4.3预读下一个令牌,如果是运算符,则设置它 作为右操作符

    2.4.4将项目的最小操作与左操作和右操作进行比较 (如果其中任何一个存在),我们可以很容易地知道这对 括号的长度是多余的,并将其输出(如果最小值为 2.4.5如果没有左操作和右操作(这也意味着 min_op=nil)且堆栈不为空,则设置top的min_op 项目作为弹出项目的最小值 例子


  • 下面的代码实现了一个简单的解决方案。它仅限于
    +
    -
    *
    /
    ,但如果需要,可以扩展到处理其他操作员

    #include <iostream>
    #include <set>
    #include <stack>
    
    int loc;
    
    std::string parser(std::string input, int _loc) {
      std::set<char> support = {'+', '-', '*', '/'};
    
      std::string expi;
      std::set<char> op;
      loc = _loc;
    
      while (true) {
        if (input[loc] == '(') {
          expi += parser(input, loc + 1);
        } else if (input[loc] == ')') {
          if ((input[loc + 1] != '*') && (input[loc + 1] != '/')) {
            return expi;
          } else {
            if ((op.find('+') == op.end()) && (op.find('-') == op.end())) {
              return expi;
            } else {
              return '(' + expi + ')';
            }
          }
        } else {
          char temp = input[loc];
          expi = expi + temp;
    
          if (support.find(temp) != support.end()) {
            op.insert(temp);
          }
        }
    
        loc++;
    
        if (loc >= input.size()) {
          break;
        }
      }
    
      return expi;
    }
    
    int main() {
      std::string input("(((a)+((b*c)))+(d*(f*g)))");
      std::cout << parser(input, 0);
    
      return 0;
    }
    
    #包括
    #包括
    #包括
    int loc;
    字符串解析器(std::字符串输入,int\u loc){
    std::set support={'+','-','*','/'};
    std::字符串表达式;
    std::set op;
    loc=_loc;
    while(true){
    如果(输入[loc]=='('){
    expi+=解析器(输入,loc+1);
    }else if(输入[loc]==')'){
    如果((输入[loc+1]!='*')和&(输入[loc+1]!='/')){
    返回表达式;
    }否则{
    如果((op.find('+')==op.end())&&(op.find('-')==op.end()){
    返回表达式;
    }否则{
    返回“(“+expi+”)”;
    }
    }
    }否则{
    字符温度=输入[loc];
    expi=expi+温度;
    if(support.find(temp)!=support.end()){
    操作插入(温度);
    }
    }
    loc++;
    如果(loc>=input.size()){
    打破
    }
    }
    返回表达式;
    }
    int main(){
    字符串输入(((a)+(b*c))+(d*(f*g)));
    
    std::cout我认为您正在寻找一种算法,如下图所示

    这个算法“几乎”已经准备好了,因为随着c语言的使用,会出现很多错误
    a*(b+c)
    
    index  left_pa  min_op left_op
    0               *      *
    1      2        +      +
    
    #include <iostream>
    #include <set>
    #include <stack>
    
    int loc;
    
    std::string parser(std::string input, int _loc) {
      std::set<char> support = {'+', '-', '*', '/'};
    
      std::string expi;
      std::set<char> op;
      loc = _loc;
    
      while (true) {
        if (input[loc] == '(') {
          expi += parser(input, loc + 1);
        } else if (input[loc] == ')') {
          if ((input[loc + 1] != '*') && (input[loc + 1] != '/')) {
            return expi;
          } else {
            if ((op.find('+') == op.end()) && (op.find('-') == op.end())) {
              return expi;
            } else {
              return '(' + expi + ')';
            }
          }
        } else {
          char temp = input[loc];
          expi = expi + temp;
    
          if (support.find(temp) != support.end()) {
            op.insert(temp);
          }
        }
    
        loc++;
    
        if (loc >= input.size()) {
          break;
        }
      }
    
      return expi;
    }
    
    int main() {
      std::string input("(((a)+((b*c)))+(d*(f*g)))");
      std::cout << parser(input, 0);
    
      return 0;
    }
    
    >>> remove_brackets("1 + (2 * 3)")
    '1 + 2 * 3'
    >>> remove_brackets("1 + (2 * 3) / 4")
    '1 + 2 * 3 / 4'
    >>> remove_brackets("1 + (2 * 3) / 4 / (5 * 6)")
    '1 + 2 * 3 / 4 / (5 * 6)'