JAVA程序设计:基本计算器 IV(LeetCode:770)

给定一个表达式 expression 如 expression = "e + 8 - a + 5" 和一个求值映射,如 {"e": 1}(给定的形式为 evalvars = ["e"] 和 evalints = [1]),返回表示简化表达式的标记列表,例如 ["-1*a","14"]

表达式交替使用块和符号,每个块和符号之间有一个空格。
块要么是括号中的表达式,要么是变量,要么是非负整数。
块是括号中的表达式,变量或非负整数。
变量是一个由小写字母组成的字符串(不包括数字)。请注意,变量可以是多个字母,并注意变量从不具有像 "2x" 或 "-x" 这样的前导系数或一元运算符 。
表达式按通常顺序进行求值:先是括号,然后求乘法,再计算加法和减法。例如,expression = "1 + 2 * 3" 的答案是 ["7"]。

输出格式如下:

对于系数非零的每个自变量项,我们按字典排序的顺序将自变量写在一个项中。例如,我们永远不会写像 “b*a*c” 这样的项,只写 “a*b*c”。
项的次数等于被乘的自变量的数目,并计算重复项。(例如,"a*a*b*c" 的次数为 4。)。我们先写出答案的最大次数项,用字典顺序打破关系,此时忽略词的前导系数。
项的前导系数直接放在左边,用星号将它与变量分隔开(如果存在的话)。前导系数 1 仍然要打印出来。
格式良好的一个示例答案是 ["-2*a*a*a", "3*a*a*b", "3*b*b", "4*a", "5*c", "-6"] 。
系数为 0 的项(包括常数项)不包括在内。例如,“0” 的表达式输出为 []。
 

示例:

输入:expression = "e + 8 - a + 5", evalvars = ["e"], evalints = [1]
输出:["-1*a","14"]

输入:expression = "e - 8 + temperature - pressure",
evalvars = ["e", "temperature"], evalints = [1, 12]
输出:["-1*pressure","5"]

输入:expression = "(e + 8) * (e - 8)", evalvars = [], evalints = []
输出:["1*e*e","-64"]

输入:expression = "7 - 7", evalvars = [], evalints = []
输出:[]

输入:expression = "a * b * c + b * a * c * 4", evalvars = [], evalints = []
输出:["5*a*b*c"]

输入:expression = "((a - b) * (b - c) + (c - a)) * ((a - b) + (b - c) * (c - a))",
evalvars = [], evalints = []
输出:["-1*a*a*b*b","2*a*a*b*c","-1*a*a*c*c","1*a*b*b*b","-1*a*b*b*c","-1*a*b*c*c","1*a*c*c*c","-1*b*b*b*c","2*b*b*c*c","-1*b*c*c*c","2*a*a*b","-2*a*a*c","-2*a*b*b","2*a*c*c","1*b*b*b","-1*b*b*c","1*b*c*c","-1*c*c*c","-1*a*a","1*a*b","1*a*c","-1*b*c"]
 

提示:

expression 的长度在 [1, 250] 范围内。
evalvars, evalints 在范围 [0, 100] 内,且长度相同。

思路:比较复杂的一道题,假如采用暴力模拟的方法需要处理的细节会很多,这道题我们可以通过分块设计能够更好的解决,我们可以定义一个多项式计算的类,从而完成计算,本题我采用官方题解的解决方法。

class Solution {
	
	class Poly{
		
		HashMap<List<String>,Integer> count;
		Poly(){count=new HashMap<>();}
		
		void update(List<String> key,int val) {
			this.count.put(key, this.count.getOrDefault(key, 0)+val);
		}
		
		Poly add(Poly that) {
			Poly ans=new Poly();
			for(List<String> k : this.count.keySet())
				ans.update(k, this.count.get(k));
			for(List<String> k : that.count.keySet())
				ans.update(k, that.count.get(k));
			return ans;
		}
		
		Poly sub(Poly that) {
			Poly ans=new Poly();
			for(List<String> k : this.count.keySet())
				ans.update(k, this.count.get(k));
			for(List<String> k : that.count.keySet())
				ans.update(k, -that.count.get(k));
			return ans;
		}
		
		Poly mul(Poly that) {
			Poly ans=new Poly();
			for(List<String> k1 : this.count.keySet())
				for(List<String> k2 : that.count.keySet()) {
					List<String> kNew=new ArrayList<>();
					for(String x : k1) kNew.add(x);
					for(String x : k2) kNew.add(x);
					Collections.sort(kNew);
					ans.update(kNew, this.count.get(k1)*that.count.get(k2));
				}
			return ans;
		}
		
		Poly evaluate(Map<String,Integer> evalMap) {
			Poly ans=new Poly();
			for(List<String> k : this.count.keySet()) {
				int c=this.count.get(k);
				List<String> free=new ArrayList<>();
				for(String token : k) {
					if(evalMap.containsKey(token))
						c*=evalMap.get(token);
					else
						free.add(token);
				}
				ans.update(free, c);
			}
			return ans;
		}
		
		int compareList(List<String> A,List<String> B) {
			int i=0;
			for(String x : A) {
				String y=B.get(i++);
				if(x.compareTo(y)!=0) 
					return x.compareTo(y);
			}
			return 0;
		}
		
		List<String> toList(){
			List<String> ans=new ArrayList<>();
			List<List<String>> keys=new ArrayList(this.count.keySet());
			Collections.sort(keys, (a,b)->
			a.size()!=b.size()?b.size()-a.size():compareList(a,b));
			
			for(List<String> key : keys) {
				int v=this.count.get(key);
				if(v==0) continue;
				StringBuilder word=new StringBuilder();
				word.append(""+v);
				for(String token : key) {
					word.append("*");
					word.append(token);
				}
				ans.add(word.toString());
			}
			return ans;
		}
	}
	
    public List<String> basicCalculatorIV(String expression, String[] evalvars, int[] evalints) {
    	
    	Map<String, Integer> evalMap=new HashMap<>();
    	for(int i=0;i<evalvars.length;i++)
    		evalMap.put(evalvars[i], evalints[i]);
    	
    	return parse(expression).evaluate(evalMap).toList();
    }
    
    public Poly parse(String expr) {
    	int i=0;	
    	List<Poly> bucket=new ArrayList<>();
    	List<Character> symbols=new ArrayList<>();
    	while(i<expr.length()) {
    		if(expr.charAt(i)=='(') {
    			int bal=0,j=i;
    			for(;j<expr.length();j++) {
    				if(expr.charAt(j)=='(') bal++;
    				if(expr.charAt(j)==')') bal--;
    				if(bal==0) break;
    			}
    			bucket.add(parse(expr.substring(i+1, j)));
    			i=j;
    		}
    		else if(Character.isLetterOrDigit(expr.charAt(i))){
    			int j=i;
    			search:{
    			for(;j<expr.length();j++)
    				if(expr.charAt(j)==' ') {
    					bucket.add(make(expr.substring(i, j)));
    					break search;
    				}
    			    bucket.add(make(expr.substring(i)));
    			}
    			i=j;
    		}
    		else if(expr.charAt(i)!=' ')
    			symbols.add(expr.charAt(i));
    		i++;
    	}
    	
    	for(int j=symbols.size()-1;j>=0;j--)
    		if(symbols.get(j)=='*')
    			bucket.set(j, combine(bucket.get(j),bucket.remove(j+1),symbols.remove(j)));
    	
    	if(bucket.isEmpty()) return new Poly();
    	Poly ans=bucket.get(0);
    	for(int j=0;j<symbols.size();j++)
    		ans=combine(ans,bucket.get(j+1),symbols.get(j));
    	
    	return ans;
    }
    
    public Poly make(String expr) {
    	Poly ans=new Poly();
    	List<String> list=new ArrayList<>();
    	if(Character.isDigit(expr.charAt(0)))
    		ans.update(list, Integer.valueOf(expr));
    	else {
    		list.add(expr);
    		ans.update(list, 1);
    	}
    	return ans;
    }
    
    public Poly combine(Poly left,Poly right,char symbol) {
    	if(symbol=='+') return left.add(right);
    	if(symbol=='-') return left.sub(right);
    	if(symbol=='*') return left.mul(right);
    	return null;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值