由操作数和二元运算符组成的表达式可以用反向波兰表示法(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
答案 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的帖子中,有两件事非常明显:
因此,您的程序应该将无效字符串转换为满足这两个条件的字符串(我跳过检查字符串是否有效的部分)。此外,应尽量减少转化次数。那么如何最小化?
以下是几个观察结果(假设字符串的长度大于2,否则它是微不足道的):
如果我们只想满足标准2.我们只需要更换几次,最多只需要插入一次。因为如果n(X)> n(*)+ 1,则将X更改为*,反之亦然。最后,如果字符串的长度是偶数,则只需插入一个X(或*)。
如果您同时想要满足条件1.,您仍需要多次替换和一次插入,但位置很重要。我们进一步可以观察到,在字符串的开头用X替换*并且在字符串的末尾用*替换X总是安全的。此外,很明显,对于有效的子字符串,我们可以将其表示为等效的X.
从上面的观察,现在很清楚,这个问题可以通过动态编程轻松解决。
因此这个问题实际上与你的算法/设计能力无关(实际上,因为比例非常小,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"));
}
}