3

An expression consisting of operands and binary operators can be written in Reverse Polish Notation (RPN) by writing both the operands followed by the operator. For example, 3 + (4 * 5) can be written as "3 4 5 * +".

You are given a string consisting of x's and *'s. x represents an operand and * represents a binary operator. It is easy to see that not all such strings represent valid RPN expressions. For example, the "x*x" is not a valid RPN expression, while "xx*" and "xxx**" are valid expressions. What is the minimum number of insert, delete and replace operations needed to convert the given string into a valid RPN expression?

Input: The first line contains the number of test cases T. T test cases follow. Each case contains a string consisting only of characters x and *.

Output: Output T lines, one for each test case containing the least number of operations needed.

Constraints: 1 <= T <= 100 The length of the input string will be at most 100.

Sample Input:

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

Sample Output:

0
0
0
2
0

Explanation:

For the first three cases, the input expression is already a valid RPN, so the answer is 0. For the fourth case, we can perform one delete, and one insert operation: xx -> xx -> xx

Manishearth
  • 14,882
  • 8
  • 59
  • 76
Peter
  • 2,719
  • 4
  • 25
  • 55

4 Answers4

3

This is one unusually big answer. I wouldn't be surprised if there exist also an elegant two-liner, but until that one is posted here's mine.

Imagine that you have a simple graph 2D, where x-axis denotes the parsing step, and y-axis denotes the difference between the current number of X's and stars, n(x)-n(*). For example, for input xx*xx** the graph would be this:

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

In order for expression to be valid this graph must never reach zero or below on y-axis, and at the end the value of y must be one (single value left on stack).

You are given three operations to be used on input expression: insert, delete, and replace. This replace operation is actually one of the two: replace x with *, and replace * with x. When you apply insert or delete somewhere in the middle of the expression the graph is changed so that from that point onward all points in graph are moved up or down. When replace is applied the points are moved up or down for two notches in the graph. One interesting note: we don't have to deal with delete operations, because the result is the same as applying the opposite insert, with the difference that inserts can be applied always and deletes only if there is a symbol available.

Your goal is to find minimal number of operations. If we would observe only the final goal (y=1) then we would determine the number of notches we have to move the graph and apply as much of replace operations as possible, and one additional insert operation. If total of N(x)-N(*) is N then number of operations would be floor((N-1)/2). The sign determines which operations are to be applied.

The problem is we must pay attention to the other condition, which is that graph must never reach zero. To determine this we must first apply previous operations on our expression. 'Insert x' is added at the start, 'insert *' comes at the end, search and replace every * with x going from start, and search and replace every x with * going from the end backwards.

After this step we have new expression. Iterate from the beginning and look for place where y=0. If there is such a place then you must insert one x before it, and compensate with inserting one * at the expression end. But remember that you already may have had done that (insert x at start, or insert * at end). If you have two inserts x then pretend it was actually replace * with x (one operation less), and forget about having to insert x. Analogously with pair of inserts *: remove two insert *, and apply one more 'replace x with *'. You really have to apply it, i.e change the expression, because if x that you find when search from end is actually before your current position then you can't apply replace, and so can't compact two insert operations into one replace.

Continue iteration until end, count for additional operations, and all the time keep in mind if you have one insert x and one insert *. That should be it. In the end you'll have a number of operations.

Dialecticus
  • 16,400
  • 7
  • 43
  • 103
0

public class 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**"));

}

}

vinkris
  • 139
  • 1
  • 6
0

Well, this is obviously one of those online code test/challenge problems for SE/SWE/SDE positions. I personally do not like this style of questions because they do nothing with your coding/algorithm/design ability but everything with whether you know the 'trick' before. As long as you know the 'trick', it is just as simple as helloworld.cpp.

So here is the trick:

From the post of Dialecticus, there are two things that are quite obvious:

  1. At any point, there should be at most (n-1) *s, if the number of X is n.
  2. The final number of * should be exactly equal to the number of X minus one.

Thus, your program should turn an invalid string into a string satisfying these two criteria (I skip the part that checks whether a string is valid). Moreover, the number of transformation should be minimized. So how to minimize?

Here are couple of observations(Assume the length of string is larger than 2, otherwise it is trivial):

  1. If we just want to satisfy criteria 2., we just need to replace several times plus do at most one insertion. Because if n(X)>n(*)+1, you change X to *, and vice versa. At last, you just insert one more X(or *) if the length of string is even.

  2. If at the same time you want to satisfy criteria 1., you still just need multiple replaces and one insertion, but the position matters. We further could observe that it is always safe to replace * with X at the beginning of the string and X with * at the end of string. Also, it is also obvious that for a valid substring, we could represent it as a equivalent X.

From the above observation, it is clear now, this problem could be solved by dynamic programming easily.

Thus this problem actually does nothing to do with your algorithm/design ability (actually as the scale is really small, 1<=T<=100, you could even solve it through brute force if you like) as long as you know that you can just do replacement and at most one insertion.

Broan
  • 63
  • 3
-1

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

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

public class 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"));


}

}

sse
  • 1,151
  • 2
  • 14
  • 26