topcoder SRM 348 Div.1 LostParentheses

本文探讨了一个算术表达式问题,该表达式由正整数、加减运算符和缺失的括号组成。目标是计算原始表达式在括号被删除后的最小可能值。文章详细介绍了解决方案,并提供了代码实现。

Problem Statement

 

We have an arithmetic expression made up of positive integers, the + and - operators and parentheses. All the parentheses, however, have been erased by the cleaning staff and we want to calculate the minimum value the original expression may have had.

You will be given a String e containing the expression without the parentheses. Return the minimum value the original expression could have had before the parentheses were erased.

Definition

 
Class:LostParentheses
Method:minResult
Parameters:String
Returns:int
Method signature:int minResult(String e)
(be sure your method is public)

Limits

 
Time limit (s):2.000
Memory limit (MB):64

Notes

-All operations in the original expression were addition and subtraction; there were no parentheses placed between two consecutive digits.

Constraints

-e will contain between 1 and 50 characters, inclusive.
-Each character of e will be a digit ('0'-'9'), a plus sign ('+') or a minus sign ('-').
-The first and last characters of e will be digits.
-No two operators (characters '+' and '-') will appear consecutively in e.
-There will not be a sequence of more than 5 consecutive digits in e.

Examples

0)

"55-50+40"
Returns: -35
The expression can only have two different values: 55-50+40=45 and 55-(50+40)=-35.


1)

"10+20+30+40"
Returns: 100
Since the sum is associative, any parenthesization of the expression would get the same result.


2)

"00009-00009"
Returns: 0
Numbers may contain leading zeroes.


This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2003, TopCoder, Inc. All rights reserved.


题目大意:给出一个算数表达式,仅包含数字(可能有前导0)和加减号,它可能漏掉了一些括号,问原式最小可能值是多少(怎么加括号可以使得它的值最小)?

题目分析:看第一眼就想到了编译原理课本上的表达式树,符号为根,数字为叶,但要怎么把所有情况遍历,就是一个问题了。换个思路立马豁然开朗,初始化结果为0,第一个数肯定是要加到结果里的,在出现减号之前,所有的数也必然要加到结果里;但是在出现减号之后,所有的数都可以通过括号的方式使得其作为减数。就是这样了。

code:

public class LostParentheses {
	//topcoder SRM 348
	public int minResult(String e){
		int index=0,num[]=new int[600];
		char[]symbol=new char[600];
		while(e.length()>1){
			int temp=0,i=0;
			char c='0';
			for(;i<e.length();i++){
				c=e.charAt(i);
				if(c>'9'||c<'0'){
					i++;
					symbol[index]=c;
					break;
				}
				temp=temp*10+c-'0';
			}
			e=e.substring(i);
			num[index++]=temp;
			//System.out.println("ans=="+temp+"\nchar=="+symbol[index-1]);
		}
		int ans=num[0];
		boolean flag=false;
		for(int i=0;i<index;i++){
			if(symbol[i]=='-')flag=true;
			if(flag)ans-=num[i+1];//已有减
			else ans+=num[i+1];
		}
		return ans;
	}
}

下面是我在豆瓣上找到的一篇解题报告,两种方法都讲了(果然有我先前想的那种),似乎是参照的国外的解题报告。

一拿到题目就想用DP来解决,但是没有成功实现,看了一下解答,提供了两种方法,一种是利用人的分析(again),另一种就是递归DP。

This problem had several possible correct approaches. Arguably the easiest of those was the following: the numbers before the first minus sign should be added to the result, and the numbers after should be subtracted, as coded by Quelloquialism. To understand why this approach works, we need to prove two facts: that this result is achievable, and that it is minimal possible. We can achieve that number by putting brackets between consecutive minuses, as follows: 3+5+7-(2+3+10)-(99+57)-(22)-(2)-(3+4) — that way all the numbers in the brackets are subtracted. We can't reduce the result even further, as the numbers before the first minus get added to the final result no matter how we put the brackets.

第一种方法:第一个减号之前的所有数都必须加到最后的结果中,而之后的所有数都可以从结果中减去,这样得到的结果是最小的,代码如下:

    boolean b = false;
    for(int i = 0; i < nums.length; i++)
    {
      if(!b) sum += nums[i];
      else sum -= nums[i];
      if(i < ee.length() && ee.charAt(i) == '-')
        b = true;
    }

相当简洁啊

If you've solved a lot of similar 'add-brackets' problems before, you could easily skip this easy solution and go for a dynamic programming one. That is, let's find the minimal possible and maximal possible values for every substring of the input string that starts and ends with a number. To find the minimum for a particular substring, we iterate over all possibilities of which operator will be evaluated last. If that operator is a '+', we need to take the minimum possible values of the strings to the left of it and to the right of it, and add them. If it's a '-', we need to take minimum on the left and maximum on the right. The maximum is computed similarly. We can evaluate the minima and maxima in the order of increasing substring length to be able to use previously computed values, or we can implement the memoizing approach, like marek.cygan did. For more information on dynamic programming, see the tutorial.

第二种方法:遍历字符串,在每个加号的两边递归求子串的最小值,在每个减号的两边递归求一个最大和一个最小值
代码如下:

int licz_max(string s);
 
int licz_min(string s){
  if (mapa_min.count(s)) return mapa_min[s];
  int res=INF;
  int n=SIZE(s);
  int jest=0;
  REP(i,n) if (s[i]=='+') res=min(res,licz_min(s.substr(0,i))+licz_min(s.substr(i+1))),jest=1;
  REP(i,n) if (s[i]=='-') res=min(res,licz_min(s.substr(0,i))-licz_max(s.substr(i+1))),jest=1;
  if (!jest) res=atoi(s.c_str());
  return mapa_min[s]=res;
}
 
int licz_max(string s){
  if (mapa_max.count(s)) return mapa_max[s];
  int res=-INF;
  int n=SIZE(s);
  int jest=0;
  REP(i,n) if (s[i]=='+') res=max(res,licz_max(s.substr(0,i))+licz_max(s.substr(i+1))),jest=1;
  REP(i,n) if (s[i]=='-') res=max(res,licz_max(s.substr(0,i))-licz_min(s.substr(i+1))),jest=1;
  if (!jest) res=atoi(s.c_str());
  return mapa_max[s]=res;
}
 
    class LostParentheses
        { 
        public: 
        int minResult(string e){ 
          return licz_min(e);
        } 

以上转自http://www.douban.com/note/157774780/

PS:算法倒是挺简单,把字符串拆成整形数组和字符数组花了不少时间,java还是不熟……



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值