以最小步数转换为正确的后缀表示法

时间:2012-04-04 15:07:30

标签: algorithm postfix-notation

由操作数和二元运算符组成的表达式可以用反向波兰表示法(RPN)编写,方法是写入操作符后跟的操作数。例如,3 +(4 * 5)可写为“3 4 5 * +”。

您将获得一个由x和*组成的字符串。 x表示操作数,*表示二元运算符。很容易看出并非所有这些字符串都代表有效的RPN表达式。例如,“x * x”不是有效的RPN表达式,而“xx *”和“xxx **”是有效的表达式。将给定字符串转换为有效的RPN表达式所需的最小插入,删除和替换操作数是多少?

输入:第一行包含测试用例数T.T测试用例如下。每个案例都包含一个仅由字符x和*组成的字符串。

输出:输出T行,每个测试用例一行,包含所需的最少操作数。

约束:1< = T< = 100输入字符串的长度最多为100。

示例输入:

5
x
xx*
xxx**
*xx
xx*xx**

示例输出:

0
0
0
2
0

说明:

对于前三种情况,输入表达式已经是有效的RPN,因此答案为0.对于第四种情况,我们可以执行一次删除和一次插入操作:xx - > xx - > XX

4 个答案:

答案 0 :(得分:3)

这是一个非常大的答案。如果还有一个优雅的双层衬里,我会不会感到惊讶,但直到那个贴在这里是我的。

想象一下,您有一个简单的图形2D,其中x轴表示解析步骤,y轴表示当前X和星数,n(x)-n(*)之间的差异。例如,对于输入xx*xx**,图形将为:

╫
╫         +
╫   +   +   +
╫ +   +       +
╬═╧═╧═╧═╧═╧═╧═╧
  x x * x x * *

为了使表达式有效,此图表必须永远不会在y轴上达到零或更低,并且在结束时y的值必须为1(堆栈上剩下单个值)。

您将在输入表达式上使用三个操作:insert,delete和replace。这个替换操作实际上是两个中的一个:将x替换为*,并将*替换为x。当您在表达式中间的某处应用插入或删除时,图形会发生变化,以便从该点开始向上或向下移动图形中的所有点。当应用替换时,点在图形中向上或向下移动两个凹口。一个有趣的注意事项:我们不必处理删除操作,因为结果与应用相反的插入操作相同,不同之处在于可以始终应用插入,只有在有符号可用时才删除。

您的目标是找到最少数量的操作。如果我们只观察最终目标(y = 1),那么我们将确定移动图表所需的槽口数量,并应用尽可能多的替换操作,以及一个额外的插入操作。如果N(x)-N(*)的总和是N,则操作次数将是下限((N-1)/ 2)。该符号决定了要应用的操作。

问题是我们必须注意其他条件,即图表必须永远不会达到零。要确定这一点,我们必须首先对表达式应用先前的操作。 '插入x'在开头添加,'insert *'出现在最后,搜索并用start从start开始替换每个*,然后搜索并用*从末尾向后替换每个x。

在这一步之后,我们有了新的表达方式。从头开始迭代并寻找y = 0的地方。如果有这样的地方,那么你必须在它之前插入一个x,并在表达式结尾插入一个*进行补偿。但请记住,您可能已经做过(在开始时插入x,或在结尾插入*)。如果你有两个插入x然后假装它实际上用x替换*(少一个操作),并忘记必须插入x。类似于一对插入*:删除两个插入*,并再应用一次'用x替换x'。你真的必须应用它,即改变表达式,因为如果从末尾搜索时找到的x实际上在当前位置之前,那么你就不能应用替换,因此无法将两个插入操作压缩成一个替换。 / p>

继续迭代直到结束,计算其他操作,并且如果你有一个插入x和一个插入*,请记住所有时间。那应该是它。最后,你将进行许多操作。

答案 1 :(得分:0)

公共类RPN {

public static boolean isValidRPN(String expr){

    char arr[] = expr.toCharArray();
    int x = 0;

    for(char c: arr){

        if ( c == 'x'){
            x++;
        }
        else if ( c == '*'){

            if ( x >= 2){
                x--;
            }
            else {
                return false;
            }
        }
    }

    if ( x == 1){
        return true;
    }

    return false;
}

//Think of RPN recursively as x(RPN)*
//The remaining code is self explanatory
private static int computeToRPN(String expr){

    int length = expr.length();

    if ( length == 1 ){
       if (expr.equals("x")){
           return 0;
       }
       else if ( expr.equals("*")){
           return 1;
       }
    }

    if ( length == 2){

        if ( expr.equals("xx") || expr.equals("*x") || expr.equals("x*")){
            return 1;
        }
        else if ( expr.equals("**")){
            return 2;
        }
    }

    char startChar = expr.charAt(0);
    char endChar = expr.charAt(expr.length()-1);

    if ( startChar == 'x' ){

        if ( endChar == 'x'){
            return 1 + compute2RPN(expr.substring(1,length-1));
        }
        else if ( endChar == '*'){
            return compute2RPN(expr.substring(1,length-1));
        }
    }

    return 2 + compute2RPN(expr.substring(1, length-1));


}

public static int compute2RPN(String expr){

    if ( isValidRPN(expr) ) return 0;
    else return computeToRPN(expr);

}

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    System.out.println(compute2RPN("xx*"));
    System.out.println(compute2RPN("xxx**"));
    System.out.println(compute2RPN("xxxx"));
    System.out.println(compute2RPN("*xx"));
    System.out.println(compute2RPN("xxxx*"));
    System.out.println(compute2RPN("**xx"));
    System.out.println(compute2RPN("xx*xx**"));

}

}

答案 2 :(得分:0)

嗯,这显然是SE / SWE / SDE职位的在线代码测试/挑战问题之一。我个人不喜欢这种问题,因为它们对你的编码/算法/设计能力没有任何作用,但是你知道这些技巧是什么。之前。只要你知道'技巧,它就像helloworld.cpp一样简单。

所以这就是诀窍:

从Dialecticus的帖子中,有两件事非常明显:

  1. 如果X的数目是n,那么在任何时候,最多应该有(n-1)* s。
  2. *的最终数字应该恰好等于X的数量减一。
  3. 因此,您的程序应该将无效字符串转换为满足这两个条件的字符串(我跳过检查字符串是否有效的部分)。此外,应尽量减少转化次数。那么如何最小化?

    以下是几个观察结果(假设字符串的长度大于2,否则它是微不足道的):

    1. 如果我们只想满足标准2.我们只需要更换几次,最多只需要插入一次。因为如果n(X)> n(*)+ 1,则将X更改为*,反之亦然。最后,如果字符串的长度是偶数,则只需插入一个X(或*)。

    2. 如果您同时想要满足条件1.,您仍需要多次替换和一次插入,但位置很重要。我们进一步可以观察到,在字符串的开头用X替换*并且在字符串的末尾用*替换X总是安全的。此外,很明显,对于有效的子字符串,我们可以将其表示为等效的X.

    3. 从上面的观察,现在很清楚,这个问题可以通过动态编程轻松解决。

      因此这个问题实际上与你的算法/设计能力无关(实际上,因为比例非常小,1< = T< = 100,如果你愿意,你甚至可以通过强力解决它),只要你知道你可以做替换,最多一次插入。

答案 3 :(得分:-1)

import java.util.HashSet; import java.util.Set; import java.util.Stack;

import org.apache.commons.lang3.mutable.MutableInt;

公共类ProperRPNConversion {

public static final char X='x';
public static final char S='*';



public static boolean isRPN(String string)
{
    char[] str=string.toCharArray();
    int count=0;
    Stack stack=new Stack();

    for(char c:str)
    {
        if(c==X)
            stack.push(c);
        else
        {
            if(stack.size()>=2)
            {
                if(((Character)stack.peek())==X)
                {
                    stack.pop();
                }
                else
                    return false;
                if(((Character)stack.peek())==X)
                {
                    stack.pop();
                }
                else
                    return false;
                stack.push(X);

            }
            else
                return false;

        }
    }

    if(stack.size()==1&&(Character)stack.peek()==X)
        return true;

    return false;

}


public static int convertToRPNSteps(String s)
{
    Set<String> curLevel=new HashSet<String>();
    Set<String> nextLevel=new HashSet<String>();
    char[] ss=s.toCharArray();
    curLevel.add(s);
    int minsteps=0;

    if(isRPN(s))
        return minsteps;

    while(curLevel.size()!=0)
    {
        minsteps++;
        for(String str:curLevel)
        {
            //delete
            int lenss=str.length();
            for(int i=0;i<lenss;i++)
            {
                String newstr=new StringBuffer(str).delete(i, i+1).toString();
                if(isRPN(newstr))
                {
                    System.out.println(s);
                    System.out.println(newstr);
                    return minsteps;
                }
                nextLevel.add(newstr);
            }
            //insert
            for(int i=0;i<=lenss;i++)
            {
                //System.out.println(i);
                //System.out.println(s);
                //System.out.println(lenss);
                String newstr=new StringBuffer(str).insert(i, X).toString();
                if(isRPN(newstr))
                {
                    System.out.println(s);
                    System.out.println(newstr);
                    return minsteps;
                }
                nextLevel.add(new StringBuffer(str).insert(i, X).toString());
                String newstr2=new StringBuffer(str).insert(i, X).toString();
                if(isRPN(newstr2))
                    return minsteps;
                nextLevel.add(newstr2);
            }

            //replace
            for(int i=0;i<lenss;i++)
            {
                StringBuffer b=new StringBuffer(str);
                if(ss[i]==X)
                    b.setCharAt(i, S);
                else
                    b.setCharAt(i, X);

                String newstr=b.toString();
                if(isRPN(newstr))
                {
                    System.out.println(s);
                    System.out.println(newstr);
                    return minsteps;
                }
                nextLevel.add(newstr);

            }

        }
        curLevel=nextLevel;
        nextLevel=new HashSet<String>();

    }
    return -1;
}





public static void main(String[] args) {

    System.out.println(convertToRPNSteps("xx*xxxx**xx*x**"));
    System.out.println(convertToRPNSteps("*xx"));


}

}