基本计算器 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”。

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

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

格式良好的一个示例答案是 ["-2aaa", "3aab", “3bb”, “4a", "5c”, “-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 = []

输出:[“1ee”,"-64"]

输入:expression = “7 - 7”,

evalvars = [], evalints = [] 输出:[]

输入:expression = “a * b * c + b * a * c * 4”,

evalvars = [], evalints = []

输出:[“5ab*c”]

输入:expression = “((a - b) * (b - c) + (c - a)) * ((a - b) + (b - c) *
(c - a))”,

evalvars = [], evalints = []

输出:["-1aabb",“2aabc”,"-1aacc",“1abbb”,"-1abbc","-1abcc",“1accc”,"-1bbbc",“2bbcc”,"-1bccc",“2aab","-2aac”,"-2abb","2acc",“1bbb","-1bbc”,“1bcc","-1ccc”,"-1aa",“1ab”,“1ac”,"-1bc"]

提示:

expression 的长度在 [1, 250] 范围内。

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

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/basic-calculator-iv

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

其实是一个多项式化简,话说之前在学数值分析的时候一直都想有这么一个玩意帮忙化简多项式,现在有了2333
直接上代码吧,主要是实现一个类,表达式解析部分参考力扣
1106.解析布尔表达式
736.Lisp 语法解析
使用拆分+递归的方式
直接上代码吧:

class Solution {

    class xiang implements Comparable<xiang> {
    	//多项式中的某一项
        List<String> bianliang;
        int xishu;

        xiang(int xishu, List<String> bianliang) {
            this.bianliang = bianliang;
            this.xishu = xishu;
        }

        @Override
        public int compareTo(xiang another) {
            if(this.bianliang.size() != another.bianliang.size()) {
                return another.bianliang.size() - this.bianliang.size();//按次数降序
            } else {
                //次数相同时按字典序升序
                for(int i = 0; i < this.bianliang.size(); ++i) {
                    int t = this.bianliang.get(i).compareTo(another.bianliang.get(i));
                    if(t != 0) {
                        return t;
                    }
                }
            }
            throw null;//因为经历了合并同类项不可能出现相同的项来着
        }
    }

    class item {
    	//多项式 要求能够求和 相乘 变成字符串
        List<xiang> xiangInItem;

        item() {
            xiangInItem = new ArrayList<>();
        }

        item(int num) {
            xiangInItem = new ArrayList<>();
            List<String> b = new ArrayList<>();
            if(num != 0)
                xiangInItem.add(new xiang(num, b));//常数
        }

        item(String s) {
            xiangInItem = new ArrayList<>();
            List<String> b = new ArrayList<>();
            b.add(s);//单独一个变量
            xiangInItem.add(new xiang(1, b));
        }

		//求和和相乘的关键都是合并同类项 用哈希表来合并同类项
		//万幸java的List是支持了合理的equals和hashCode的
        item multiply(item another) {
            //有挑战性的地方 其实写了写也不是很有挑战
            HashMap<List<String>, Integer> ret = new HashMap<>();
            for(xiang x : xiangInItem)
            for(xiang y : another.xiangInItem) {
                List<String> bianliang = new ArrayList<>(x.bianliang);
                bianliang.addAll(y.bianliang);
                Collections.sort(bianliang);//按字典序排列一个项中的变量
                ret.compute(bianliang, (k, v)-> v == null ? x.xishu * y.xishu : v + x.xishu * y.xishu);
            }
            item rret = new item();
            for(var entry : ret.entrySet()) {
                if(entry.getValue() != 0)
                    rret.xiangInItem.add(new xiang(entry.getValue(), entry.getKey()));
            }
            return rret;
        }

        item add(item another, int pos) {
            //如果两个项 只涉及合并同类项和
            //pos取值为 1 或 -1
            HashMap<List<String>, Integer> ret = new HashMap<>();
            for(xiang x : xiangInItem) {
                ret.put(x.bianliang, x.xishu);
            }

            for(xiang x : another.xiangInItem) {
                ret.compute(x.bianliang, (k, v)->v == null ? x.xishu * pos : x.xishu * pos + v);
            }

            item rret = new item();
            for(var entry : ret.entrySet()) {
                if(entry.getValue() != 0)
                    rret.xiangInItem.add(new xiang(entry.getValue(), entry.getKey()));
            }
            return rret;
        }

        List<String> toStringList() {
            List<String> ret = new ArrayList<>();
            Collections.sort(xiangInItem);
            for(xiang x : xiangInItem) {
                StringBuilder b = new StringBuilder();
                b.append(x.xishu);
                for(String s : x.bianliang) {
                    b.append('*');
                    b.append(s);
                }
                ret.add(b.toString());
            }
            return ret;
        }
    }

    HashMap<String, Integer> eva;

    int itemEnd(String s, int beg) {
        //返回这个item后紧挨着的空格的位置
        if(s.charAt(beg) != '(') {
            while(beg < s.length() && s.charAt(beg) != ' ') {
                ++beg;
            }
        } else {
            int left = 1;
            ++beg;
            while(left > 0) {
                if(s.charAt(beg) == '(') {
                    ++left;
                } else if(s.charAt(beg) == ')') {
                    --left;
                }
                ++beg;
            }
        }
        return beg;
    }

    item computeItem(String s) {
        //从字符串转化为item
        int beg = 0;
        int end = itemEnd(s, beg);
        if(end == s.length()) {
            //整个字符串只有一个条目 要么是括号括起来的一大堆 要么是一个单条
            if(s.charAt(0) == '(') {
                return computeItem(s.substring(1, s.length() - 1));
            }
            //单条可能是 字母 数 单独的变量
            if(s.charAt(0) >= '0' && s.charAt(0) <= '9') {
                //整个是一个数字
                return new item(Integer.valueOf(s));
            } else if(eva.containsKey(s)) {
                return new item(eva.get(s));
            } else {
                return new item(s);
            }
        }

        item cur = computeItem(s.substring(0, end));
        beg = end;
        //end不是结尾 有若干个
        //智力不够 先扫描一遍把乘号料理了 最后处理加减
        List<item> items = new ArrayList<>();
        List<Character> letters = new ArrayList<>();
        while(beg < s.length()) {
        	//在第一遍扫描的时候先把乘号料理了
            char c = s.charAt(++beg);
            beg += 2;
            end = itemEnd(s, beg);
            item next = computeItem(s.substring(beg, end));
            beg = end;
            if(c == '*') {
                cur = cur.multiply(next);
            } else {
                items.add(cur);
                letters.add(c);
                cur = next;
            }
        }
        items.add(cur);
        //只有加号和减号
        item ret = items.get(0);
        for(int i = 0; i < letters.size(); ++i) {
            ret = ret.add(items.get(i + 1), letters.get(i) == '+' ? 1 : -1);
        }
        return ret;
    }

    public List<String> basicCalculatorIV(String expression, String[] evalvars, int[] evalints) {
        eva = new HashMap<>();
        for(int i = 0; i < evalvars.length; ++i) {
            eva.put(evalvars[i], evalints[i]);
        }
        return computeItem(expression).toStringList();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值