770. 基本计算器 IV

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

表达式交替使用块和符号,每个块和符号之间有一个空格。

块要么是括号中的表达式,要么是变量,要么是非负整数。

块是括号中的表达式,变量或非负整数。

变量是一个由小写字母组成的字符串(不包括数字)。请注意,变量可以是多个字母,并注意变量从不具有像 “2x” 或 “-x” 这样的前导系数或一元运算符 。

表达式按通常顺序进行求值:先是括号,然后求乘法,再计算加法和减法。例如,expression = “1 + 2 * 3” 的答案是 [“7”]。

输出格式如下:

对于系数非零的每个自变量项,我们按字典排序的顺序将自变量写在一个项中。例如,我们永远不会写像 “bac” 这样的项,只写 “abc”。

项的次数等于被乘的自变量的数目,并计算重复项。(例如,“aabc" 的次数为 4。)。我们先写出答案的最大次数项,用字典顺序打破关系,此时忽略词的前导系数。

项的前导系数直接放在左边,用星号将它与变量分隔开(如果存在的话)。前导系数 1 仍然要打印出来。

格式良好的一个示例答案是 ["-2
aaa”, “3aab", "3bb", "4a”, “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] 内,且长度相同。

PS:

首先这个题,先别慌,(尽管我很慌o(><;)oo),但是一定要理性分析,

我们把所有的方法分开,他就是让我们把这个式子分开,常数和变量的数分开,这可能是我这种笨蛋读了十分钟才读懂题目,

class Solution {
public List<String> basicCalculatorIV(String expression, String[] evalvars, int[] evalints) {
HashMap<String,Integer>map=new HashMap<>();
for (int i = 0; i <evalvars.length ; i++) {
map.put(evalvars[i],evalints[i]);
}
LinkedList<Expr> mainStack=new LinkedList();//存数字,变量
LinkedList<String> opStack=new LinkedList<>();//存符号
int i=0,len=expression.length();char [] str=expression.toCharArray();
while (i<len)
{
if (str[i]==' '){i++;continue;}
else if (Character.isDigit(str[i])){ //获取数字
int x=0;
while (i<len&&Character.isDigit(str[i]))
{x=10*x+str[i]-'0';i++;}//统计数字的常用模板
mainStack.push(new Expr(new Item(x)));
}else if (str[i]>='a'&&str[i]<='z')
{
StringBuilder sb=new StringBuilder();
while (i<len&&(str[i]>='a'&&str[i]<='z'))
{sb.append(str[i]);i++;}
String s=sb.toString();
if (map.containsKey(s))//如果该变量有值
{ //变量变数字
mainStack.push(new Expr(new Item(map.get(s))));
}else {
//创建变量多项式
mainStack.push(new Expr(new Item(1,s)));
}
//左括号直接入栈
}else if (str[i]=='('){opStack.push("(");i++;}
else if (str[i]==')'){
//遇到有括号,则不停出栈,运算,直到遇到左括号为止
while (!opStack.isEmpty()&&!opStack.peek().equals("(")){
String op=opStack.pop();
Expr expr2=mainStack.pop();
Expr expr1=mainStack.pop();
mainStack.push(expr1.operate(expr2,op));
} opStack.pop();i++;//左括号出栈,指针移动
}else if (str[i]=='*'){
while (!opStack.isEmpty()&&opStack.peek().equals("*"))
{
//如果栈顶为乘号,先计算乘号,把乘法处理完
String op=opStack.pop();
Expr expr2=mainStack.pop();
Expr expr1=mainStack.pop();
mainStack.push(expr1.operate(expr2,op));
}opStack.push("*");i++;//再入栈
}else { //把前驱的加减号处理完
while (!opStack.isEmpty()&&(opStack.peek().equals("+")||
opStack.peek().equals("-")||opStack.peek().equals("*"))){
String op=opStack.pop();
Expr expr2=mainStack.pop();
Expr expr1=mainStack.pop();
mainStack.push(expr1.operate(expr2,op));
}opStack.push(str[i]=='+'?"+":"-");i++;
}
}
while (!opStack.isEmpty())
{ //处理后缀表达式
String op=opStack.pop();
Expr expr2=mainStack.pop();
Expr expr1=mainStack.pop();
mainStack.push(expr1.operate(expr2,op));
}
List<String> res=new ArrayList<>();
Expr expr=mainStack.pop();
expr.clean();
for (Item item:expr.items)res.add(item.toString());
return res; }
} //单项式
class Item implements Comparable<Item>{
int coeff; //单项式系数
ArrayList<String> factors;//单项式字母 public Item(int coeff) {
this.coeff = coeff;factors=new ArrayList<>();
} public Item() {
this.factors = new ArrayList<>();
coeff=0;
} public Item(int coeff, String f) {
this.coeff = coeff;
this.factors = new ArrayList<>();
factors.add(f);
} @Override
public String toString() {
StringBuilder sb=new StringBuilder();
sb.append(coeff);
for (String s:factors)
{sb.append("*").append(s);}
return sb.toString();
} @Override
public int compareTo(Item item) {
if (this.factors.size()==item.factors.size())//如果两个单项式字母长度相等
{
int i=0,len=this.factors.size();//按照字典顺序比较
while (i<len&&factors.get(i).compareTo(item.factors.get(i))==0)i++;
return i==len?0:factors.get(i).compareTo(item.factors.get(i));
}else {
//按长度从大到小排位
return item.factors.size()-factors.size(); }
}
//单项式相乘
Item mutil(Item item){
Item res=new Item();
res.coeff=coeff*item.coeff;//乘系数
res.factors.addAll(factors);
res.factors.addAll(item.factors); //合并字母
res.factors.sort(String::compareTo);//排序
return res;
}
}
//多项式:由多个单项式组成
class Expr{
ArrayList<Item> items; //单项式列表 public Expr(Item item) {
this.items = new ArrayList<>();
items.add(item);
}
void add(Expr expr){ //将另外多项式的项直接合并过来
items.addAll(expr.items);
items.sort(Item::compareTo);//排序
clean();//去除冗余项
}
void mul(Expr expr){
ArrayList<Item> res=new ArrayList<>();
for (Item item1:items)
for (Item item2:expr.items)
res.add(item1.mutil(item2)); //将每一项按乘法规则相乘
this.items=res;
items.sort(Item::compareTo);
clean();
} Expr clean(){ //去除冗余同项
int i=0;
for (; i <items.size(); i++) {
//对于每个单项式,比较前后两个
while (i+1<items.size()&&items.get(i).compareTo(items.get(i+1))==0)
{
//如果前后两个单项式字母相等,则合并,并删除靠后的一个
items.get(i).coeff+=items.get(i+1).coeff;
items.remove(i+1);
}
//如果单项式系数=0 删除该项
if (i<items.size()&&items.get(i).coeff==0)
items.remove(i--);
}
return this;
} Expr operate(Expr expr,String op){
switch (op){
case "*":mul(expr);break;
case "+":add(expr);break;
case "-":
for (Item item:expr.items)
item.coeff*=-1;
add(expr);
;break;
}
return this; } }

Java实现 LeetCode 770 基本计算器 IV(暴力+分析题)的更多相关文章

  1. Java实现 LeetCode 816 模糊坐标(暴力)

    816. 模糊坐标 我们有一些二维坐标,如 "(1, 3)" 或 "(2, 0.5)",然后我们移除所有逗号,小数点和空格,得到一个字符串S.返回所有可能的原始 ...

  2. Java实现 LeetCode 227 基本计算器 II(二)

    227. 基本计算器 II 实现一个基本的计算器来计算一个简单的字符串表达式的值. 字符串表达式仅包含非负整数,+, - ,*,/ 四种运算符和空格 . 整数除法仅保留整数部分. 示例 1: 输入: ...

  3. Java实现 LeetCode 224 基本计算器

    224. 基本计算器 实现一个基本的计算器来计算一个简单的字符串表达式的值. 字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 . 示例 1: 输入: "1 ...

  4. Java实现 LeetCode 836 矩形重叠(暴力)

    836. 矩形重叠 矩形以列表 [x1, y1, x2, y2] 的形式表示,其中 (x1, y1) 为左下角的坐标,(x2, y2) 是右上角的坐标. 如果相交的面积为正,则称两矩形重叠.需要明确的 ...

  5. Java实现 LeetCode 835 图像重叠(暴力)

    835. 图像重叠 给出两个图像 A 和 B ,A 和 B 为大小相同的二维正方形矩阵.(并且为二进制矩阵,只包含0和1). 我们转换其中一个图像,向左,右,上,或下滑动任何数量的单位,并把它放在另一 ...

  6. Java实现 LeetCode 824 山羊拉丁文(暴力)

    824. 山羊拉丁文 给定一个由空格分割单词的句子 S.每个单词只包含大写或小写字母. 我们要将句子转换为 "Goat Latin"(一种类似于 猪拉丁文 - Pig Latin ...

  7. Java实现 LeetCode 817 链表组件(暴力)

    817. 链表组件 给定一个链表(链表结点包含一个整型值)的头结点 head. 同时给定列表 G,该列表是上述链表中整型值的一个子集. 返回列表 G 中组件的个数,这里对组件的定义为:链表中一段最长连 ...

  8. Java实现 LeetCode 808 分汤 (暴力模拟)

    808. 分汤 有 A 和 B 两种类型的汤.一开始每种类型的汤有 N 毫升.有四种分配操作: 提供 100ml 的汤A 和 0ml 的汤B. 提供 75ml 的汤A 和 25ml 的汤B. 提供 5 ...

  9. Java实现 LeetCode 799 香槟塔 (暴力模拟)

    799. 香槟塔 我们把玻璃杯摆成金字塔的形状,其中第一层有1个玻璃杯,第二层有2个,依次类推到第100层,每个玻璃杯(250ml)将盛有香槟. 从顶层的第一个玻璃杯开始倾倒一些香槟,当顶层的杯子满了 ...

随机推荐

  1. Directory类和DirectoryInfo类

    1.Directory类 Directory类公开了用于创建.移动.枚举.删除目录和子目录的静态方法 2.DirectoryInfo类 DirectoryInfo和Directory类的区别可以参看F ...

  2. 今天主要做的是Remember Me(记住我)功能的实现

    功能就是让网站登录过的人只要不注销,下次打开网站之后直接进入,不用重复登录,此功能主要是session与cookie的配合运用,具体实现是这样的,在登录页面判断并完成登录,然后将所需数据写入sessi ...

  3. NFS服务器搭建-共享PC与ARM主板文件

    NFS服务器搭建-共享PC与ARM主板文件 在搭建好交叉编译环境之后需要实现目标板与宿主机的文件共享,在这里选择NFS,由于资料较多.需要注意的以下几点: 目标板与宿主机需要连接在同一个网段内. 宿主 ...

  4. 为什么PUSH推送要经常背锅?

    前言 只有光头才能变强. 文本已收录至我的GitHub精选文章,欢迎Star:https://github.com/ZhongFuCheng3y/3y 自从做了推送以后,每隔一段时间就发现有各大的公司 ...

  5. 使用Python创建一个系统监控程序--李渣渣(lizaza.cn)

    最近在做个人网站,但是由于服务器资源不足,偶尔会出现系统崩溃的现象,所以想写一个程序来实时监控系统状态.当系统资源占用过高时发送邮件提醒. psutil(进程和系统实用程序)是一个跨平台的库,用于检索 ...

  6. Web_php_unserialize-攻防世界XCTF

    0x00 简介 记录一下,重点是记录一下那篇正则文章. 0x01 题目代码 <?php class Demo { private $file = 'index.php'; public func ...

  7. shiro 实现自定义权限规则校验

    <span style="font-family: Arial, Helvetica, sans-serif;">在系统中使用shiro进行权限管理,当用户访问没有权限 ...

  8. 【SMB源码解析系列】——001.JumpEngine函数

    在SMB的源码中大概有不到20处看起来很奇怪的指令,它的格式是通过jsr指令调用一个名为JumpEngine的函数,其后并不是跟随某些后续的逻辑指令,而是通过.dw定义了一系列16位地址. 我们可以看 ...

  9. vue富文本编辑器TinyMec才是最好用的

    最近在做一个后台管理系统,系统中需要一个编辑器,没多想,百度查之,找了好些.如下: UEditor CKEditor 4 Vue-html5-editor wangeditor quill .... ...

  10. 我,不是说了PID要平均值吗?

    前几日写了一篇PID算法学习笔记,并幻想了一个场景进行算法仿真.经过不断探索后,博主发现,PID算法的精髓不在算法逻辑,而在于PID三个参数的值.本篇随笔将延续上次的仿真实验进行调试,总结PID调参的 ...