|  | 
| 1 | 1 | package g0701_0800.s0770_basic_calculator_iv; | 
| 2 | 2 | 
 | 
| 3 | 3 | // #Hard #String #Hash_Table #Math #Stack #Recursion | 
| 4 |  | -// #2025_04_17_Time_8_ms_(95.70%)_Space_45.18_MB_(49.46%) | 
|  | 4 | +// #2025_04_18_Time_8_ms_(95.70%)_Space_44.97_MB_(82.80%) | 
| 5 | 5 | 
 | 
| 6 | 6 | import java.util.ArrayList; | 
| 7 |  | -import java.util.Arrays; | 
| 8 | 7 | import java.util.Collections; | 
| 9 |  | -import java.util.Comparator; | 
| 10 | 8 | import java.util.HashMap; | 
| 11 | 9 | import java.util.List; | 
| 12 | 10 | import java.util.Map; | 
| 13 |  | -import java.util.TreeMap; | 
| 14 | 11 | 
 | 
| 15 | 12 | public class Solution { | 
| 16 |  | -    private String s; | 
| 17 |  | -    private char[] arr; | 
| 18 |  | -    private int[] braces; | 
| 19 |  | -    private final Map<String, Integer> variables = new HashMap<>(); | 
|  | 13 | +    private static class Result { | 
|  | 14 | +        private Map<List<String>, Integer> map; | 
| 20 | 15 | 
 | 
| 21 |  | -    public List<String> basicCalculatorIV(String expression, String[] evalvars, int[] evalints) { | 
| 22 |  | -        s = expression; | 
| 23 |  | -        arr = s.toCharArray(); | 
| 24 |  | -        int n = arr.length; | 
| 25 |  | -        braces = new int[n]; | 
| 26 |  | -        Arrays.fill(braces, -1); | 
| 27 |  | -        int[] stack = new int[n / 2]; | 
| 28 |  | -        int index = -1; | 
| 29 |  | -        for (int i = 0; i < n; ++i) { | 
| 30 |  | -            if (arr[i] == '(') { | 
| 31 |  | -                stack[++index] = i; | 
| 32 |  | -            } else if (arr[i] == ')') { | 
| 33 |  | -                int last = stack[index--]; | 
| 34 |  | -                braces[last] = i; | 
| 35 |  | -                braces[i] = last; | 
| 36 |  | -            } | 
|  | 16 | +        Result() { | 
|  | 17 | +            map = new HashMap<>(); | 
|  | 18 | +        } | 
|  | 19 | + | 
|  | 20 | +        Result(Map<List<String>, Integer> map) { | 
|  | 21 | +            this.map = map; | 
|  | 22 | +        } | 
|  | 23 | + | 
|  | 24 | +        void update(List<String> key, int val) { | 
|  | 25 | +            map.put(key, map.getOrDefault(key, 0) + val); | 
|  | 26 | +        } | 
|  | 27 | + | 
|  | 28 | +        Map<List<String>, Integer> getMap() { | 
|  | 29 | +            return map; | 
| 37 | 30 |         } | 
| 38 |  | -        for (int i = 0; i < evalvars.length; ++i) { | 
| 39 |  | -            variables.put(evalvars[i], evalints[i]); | 
| 40 |  | -        } | 
| 41 |  | -        List<Term> terms = dewIt(0, n - 1); | 
| 42 |  | -        Map<String, Integer> map = | 
| 43 |  | -                new TreeMap<>( | 
| 44 |  | -                        new Comparator<>() { | 
| 45 |  | -                            public int compare(String a, String b) { | 
| 46 |  | -                                int ca = countStars(a); | 
| 47 |  | -                                int cb = countStars(b); | 
| 48 |  | -                                if (ca != cb) { | 
| 49 |  | -                                    return cb - ca; | 
| 50 |  | -                                } else { | 
| 51 |  | -                                    return a.compareTo(b); | 
| 52 |  | -                                } | 
| 53 |  | -                            } | 
| 54 |  | - | 
| 55 |  | -                            private int countStars(String s) { | 
| 56 |  | -                                int ans = 0; | 
| 57 |  | -                                for (char c : s.toCharArray()) { | 
| 58 |  | -                                    if (c == '*') { | 
| 59 |  | -                                        ++ans; | 
| 60 |  | -                                    } | 
| 61 |  | -                                } | 
| 62 |  | -                                return ans; | 
| 63 |  | -                            } | 
| 64 |  | -                        }); | 
| 65 |  | -        for (Term term : terms) { | 
| 66 |  | -            if (term.coeff != 0) { | 
| 67 |  | -                String key = term.getKey(); | 
| 68 |  | -                if (map.containsKey(key)) { | 
| 69 |  | -                    int oldCoeff = map.get(key); | 
| 70 |  | -                    if (oldCoeff == -term.coeff) { | 
| 71 |  | -                        map.remove(key); | 
| 72 |  | -                    } else { | 
| 73 |  | -                        map.put(key, oldCoeff + term.coeff); | 
| 74 |  | -                    } | 
| 75 |  | -                } else { | 
| 76 |  | -                    map.put(key, term.coeff); | 
|  | 31 | + | 
|  | 32 | +        List<String> toList() { | 
|  | 33 | +            List<List<String>> keyList = new ArrayList<>(map.keySet()); | 
|  | 34 | +            Map<List<String>, String> list2String = new HashMap<>(); | 
|  | 35 | +            for (List<String> key : keyList) { | 
|  | 36 | +                StringBuilder sb = new StringBuilder(); | 
|  | 37 | +                for (String k : key) { | 
|  | 38 | +                    sb.append(k).append("*"); | 
|  | 39 | +                } | 
|  | 40 | +                list2String.put(key, sb.toString()); | 
|  | 41 | +            } | 
|  | 42 | +            keyList.sort( | 
|  | 43 | +                    (a, b) -> | 
|  | 44 | +                            (a.size() == b.size() | 
|  | 45 | +                                    ? list2String.get(a).compareTo(list2String.get(b)) | 
|  | 46 | +                                    : b.size() - a.size())); | 
|  | 47 | +            List<String> res = new ArrayList<>(); | 
|  | 48 | +            for (List<String> key : keyList) { | 
|  | 49 | +                if (map.get(key) == 0) { | 
|  | 50 | +                    continue; | 
|  | 51 | +                } | 
|  | 52 | +                StringBuilder sb = new StringBuilder(); | 
|  | 53 | +                sb.append(map.get(key)); | 
|  | 54 | +                for (String k : key) { | 
|  | 55 | +                    sb.append("*").append(k); | 
| 77 | 56 |                 } | 
|  | 57 | +                res.add(sb.toString()); | 
| 78 | 58 |             } | 
|  | 59 | +            return res; | 
| 79 | 60 |         } | 
| 80 |  | -        List<String> ans = new ArrayList<>(); | 
| 81 |  | -        for (Map.Entry<String, Integer> entry : map.entrySet()) { | 
| 82 |  | -            ans.add(entry.getValue() + entry.getKey()); | 
|  | 61 | +    } | 
|  | 62 | + | 
|  | 63 | +    private Map<String, Integer> evalMap; | 
|  | 64 | +    private int i = 0; | 
|  | 65 | + | 
|  | 66 | +    public List<String> basicCalculatorIV(String expression, String[] evalvars, int[] evalints) { | 
|  | 67 | +        evalMap = new HashMap<>(); | 
|  | 68 | +        for (int j = 0; j < evalvars.length; j++) { | 
|  | 69 | +            evalMap.put(evalvars[j], evalints[j]); | 
| 83 | 70 |         } | 
| 84 |  | -        return ans; | 
|  | 71 | +        i = -1; | 
|  | 72 | +        next(expression); | 
|  | 73 | +        Result res = expression(expression); | 
|  | 74 | +        return res.toList(); | 
| 85 | 75 |     } | 
| 86 | 76 | 
 | 
| 87 |  | -    private List<Term> dewIt(int a, int b) { | 
| 88 |  | -        if (braces[a] == b) { | 
| 89 |  | -            return dewIt(a + 1, b - 1); | 
| 90 |  | -        } | 
| 91 |  | -        List<Term> ans = new ArrayList<>(); | 
| 92 |  | -        List<Term> buffer = new ArrayList<>(); | 
| 93 |  | -        buffer.add(new Term(1, new ArrayList<>())); | 
| 94 |  | -        int i = a; | 
| 95 |  | -        while (i <= b) { | 
| 96 |  | -            int j = i; | 
| 97 |  | -            List<Term> curr; | 
| 98 |  | -            if (arr[i] == '(') { | 
| 99 |  | -                j = braces[i] + 1; | 
| 100 |  | -                curr = dewIt(i + 1, j - 2); | 
|  | 77 | +    private Result expression(String s) { | 
|  | 78 | +        Result res = term(s); | 
|  | 79 | +        while (i < s.length() && (s.charAt(i) == '+' || s.charAt(i) == '-')) { | 
|  | 80 | +            int c = s.charAt(i); | 
|  | 81 | +            next(s); | 
|  | 82 | +            if (c == '+') { | 
|  | 83 | +                res = add(res, term(s)); | 
| 101 | 84 |             } else { | 
| 102 |  | -                while (j <= b && arr[j] != ' ') { | 
| 103 |  | -                    ++j; | 
| 104 |  | -                } | 
| 105 |  | -                String exp = s.substring(i, j); | 
| 106 |  | -                int val = 1; | 
| 107 |  | -                List<String> vars = new ArrayList<>(); | 
| 108 |  | -                if (variables.containsKey(exp)) { | 
| 109 |  | -                    val = variables.get(exp); | 
| 110 |  | -                } else if (exp.charAt(0) <= '9') { | 
| 111 |  | -                    val = Integer.parseInt(exp); | 
| 112 |  | -                } else { | 
| 113 |  | -                    vars.add(exp); | 
| 114 |  | -                } | 
| 115 |  | -                curr = new ArrayList<>(); | 
| 116 |  | -                curr.add(new Term(val, vars)); | 
|  | 85 | +                res = subtract(res, term(s)); | 
| 117 | 86 |             } | 
| 118 |  | -            buffer = multiply(buffer, curr); | 
| 119 |  | -            if (j > b || arr[j + 1] == '+' || arr[j + 1] == '-') { | 
| 120 |  | -                ans.addAll(buffer); | 
| 121 |  | -                buffer = new ArrayList<>(); | 
| 122 |  | -            } | 
| 123 |  | -            if (j < b) { | 
| 124 |  | -                ++j; | 
| 125 |  | -                if (arr[j] == '+') { | 
| 126 |  | -                    buffer.add(new Term(1, new ArrayList<>())); | 
| 127 |  | -                } else if (arr[j] == '-') { | 
| 128 |  | -                    buffer.add(new Term(-1, new ArrayList<>())); | 
| 129 |  | -                } | 
| 130 |  | -                j += 2; | 
| 131 |  | -            } | 
| 132 |  | -            i = j; | 
| 133 | 87 |         } | 
| 134 |  | -        return ans; | 
|  | 88 | +        return res; | 
| 135 | 89 |     } | 
| 136 | 90 | 
 | 
| 137 |  | -    private List<Term> multiply(List<Term> a, List<Term> b) { | 
| 138 |  | -        List<Term> ans = new ArrayList<>(); | 
| 139 |  | -        for (Term x : a) { | 
| 140 |  | -            for (Term y : b) { | 
| 141 |  | -                Term prod = x.copy(); | 
| 142 |  | -                prod.multiply(y); | 
| 143 |  | -                ans.add(prod); | 
|  | 91 | +    private Result term(String s) { | 
|  | 92 | +        Result res = factor(s); | 
|  | 93 | +        while (i < s.length() && s.charAt(i) == '*') { | 
|  | 94 | +            next(s); | 
|  | 95 | +            res = multiply(res, factor(s)); | 
|  | 96 | +        } | 
|  | 97 | +        return res; | 
|  | 98 | +    } | 
|  | 99 | + | 
|  | 100 | +    private Result multiply(Result r1, Result r2) { | 
|  | 101 | +        Map<List<String>, Integer> map1 = r1.getMap(); | 
|  | 102 | +        Map<List<String>, Integer> map2 = r2.getMap(); | 
|  | 103 | +        Map<List<String>, Integer> map = new HashMap<>(); | 
|  | 104 | +        for (Map.Entry<List<String>, Integer> entry1 : map1.entrySet()) { | 
|  | 105 | +            for (Map.Entry<List<String>, Integer> entry2 : map2.entrySet()) { | 
|  | 106 | +                List<String> key = new ArrayList<>(entry1.getKey()); | 
|  | 107 | +                key.addAll(entry2.getKey()); | 
|  | 108 | +                Collections.sort(key); | 
|  | 109 | +                map.put(key, map.getOrDefault(key, 0) + entry1.getValue() * entry2.getValue()); | 
| 144 | 110 |             } | 
| 145 | 111 |         } | 
| 146 |  | -        return ans; | 
|  | 112 | +        return new Result(map); | 
| 147 | 113 |     } | 
| 148 | 114 | 
 | 
| 149 |  | -    private static class Term { | 
| 150 |  | -        int coeff; | 
| 151 |  | -        List<String> vars; | 
|  | 115 | +    private Result add(Result r1, Result r2) { | 
|  | 116 | +        Map<List<String>, Integer> map1 = r1.getMap(); | 
|  | 117 | +        Map<List<String>, Integer> map2 = r2.getMap(); | 
|  | 118 | +        Map<List<String>, Integer> map = new HashMap<>(); | 
|  | 119 | +        for (Map.Entry<List<String>, Integer> entry1 : map1.entrySet()) { | 
|  | 120 | +            map.put(entry1.getKey(), map.getOrDefault(entry1.getKey(), 0) + entry1.getValue()); | 
|  | 121 | +        } | 
|  | 122 | +        for (Map.Entry<List<String>, Integer> entry2 : map2.entrySet()) { | 
|  | 123 | +            map.put(entry2.getKey(), map.getOrDefault(entry2.getKey(), 0) + entry2.getValue()); | 
|  | 124 | +        } | 
|  | 125 | +        return new Result(map); | 
|  | 126 | +    } | 
| 152 | 127 | 
 | 
| 153 |  | -        public Term(int a, List<String> c) { | 
| 154 |  | -            this.coeff = a; | 
| 155 |  | -            vars = new ArrayList<>(); | 
| 156 |  | -            vars.addAll(c); | 
|  | 128 | +    private Result subtract(Result r1, Result r2) { | 
|  | 129 | +        Map<List<String>, Integer> map1 = r1.getMap(); | 
|  | 130 | +        Map<List<String>, Integer> map2 = r2.getMap(); | 
|  | 131 | +        Map<List<String>, Integer> map = new HashMap<>(); | 
|  | 132 | +        for (Map.Entry<List<String>, Integer> entry1 : map1.entrySet()) { | 
|  | 133 | +            map.put(entry1.getKey(), map.getOrDefault(entry1.getKey(), 0) + entry1.getValue()); | 
|  | 134 | +        } | 
|  | 135 | +        for (Map.Entry<List<String>, Integer> entry2 : map2.entrySet()) { | 
|  | 136 | +            map.put(entry2.getKey(), map.getOrDefault(entry2.getKey(), 0) - entry2.getValue()); | 
| 157 | 137 |         } | 
|  | 138 | +        return new Result(map); | 
|  | 139 | +    } | 
| 158 | 140 | 
 | 
| 159 |  | -        public String getKey() { | 
| 160 |  | -            StringBuilder b = new StringBuilder(); | 
| 161 |  | -            Collections.sort(vars); | 
| 162 |  | -            for (String x : vars) { | 
| 163 |  | -                b.append('*'); | 
| 164 |  | -                b.append(x); | 
| 165 |  | -            } | 
| 166 |  | -            return b.toString(); | 
|  | 141 | +    private Result factor(String s) { | 
|  | 142 | +        Result res = new Result(); | 
|  | 143 | +        if (s.charAt(i) == '(') { | 
|  | 144 | +            next(s); | 
|  | 145 | +            res = expression(s); | 
|  | 146 | +            next(s); | 
|  | 147 | +            return res; | 
| 167 | 148 |         } | 
|  | 149 | +        if (Character.isLowerCase(s.charAt(i))) { | 
|  | 150 | +            return identifier(s); | 
|  | 151 | +        } | 
|  | 152 | +        res.update(new ArrayList<>(), number(s)); | 
|  | 153 | +        return res; | 
|  | 154 | +    } | 
| 168 | 155 | 
 | 
| 169 |  | -        public void multiply(Term that) { | 
| 170 |  | -            this.coeff *= that.coeff; | 
| 171 |  | -            if (this.coeff == 0) { | 
| 172 |  | -                vars.clear(); | 
| 173 |  | -            } else { | 
| 174 |  | -                this.vars.addAll(that.vars); | 
| 175 |  | -            } | 
|  | 156 | +    private Result identifier(String s) { | 
|  | 157 | +        Result res = new Result(); | 
|  | 158 | +        StringBuilder sb = new StringBuilder(); | 
|  | 159 | +        while (i < s.length() && Character.isLowerCase(s.charAt(i))) { | 
|  | 160 | +            sb.append(s.charAt(i)); | 
|  | 161 | +            i++; | 
|  | 162 | +        } | 
|  | 163 | +        i--; | 
|  | 164 | +        next(s); | 
|  | 165 | +        String variable = sb.toString(); | 
|  | 166 | +        if (evalMap.containsKey(variable)) { | 
|  | 167 | +            res.update(new ArrayList<>(), evalMap.get(variable)); | 
|  | 168 | +        } else { | 
|  | 169 | +            List<String> key = new ArrayList<>(); | 
|  | 170 | +            key.add(variable); | 
|  | 171 | +            res.update(key, 1); | 
| 176 | 172 |         } | 
|  | 173 | +        return res; | 
|  | 174 | +    } | 
|  | 175 | + | 
|  | 176 | +    private int number(String s) { | 
|  | 177 | +        int res = 0; | 
|  | 178 | +        while (i < s.length() && s.charAt(i) >= '0' && s.charAt(i) <= '9') { | 
|  | 179 | +            res = res * 10 + (s.charAt(i) - '0'); | 
|  | 180 | +            i++; | 
|  | 181 | +        } | 
|  | 182 | +        i--; | 
|  | 183 | +        next(s); | 
|  | 184 | +        return res; | 
|  | 185 | +    } | 
| 177 | 186 | 
 | 
| 178 |  | -        public Term copy() { | 
| 179 |  | -            return new Term(coeff, vars); | 
|  | 187 | +    private void next(String s) { | 
|  | 188 | +        i++; | 
|  | 189 | +        while (i < s.length() && s.charAt(i) == ' ') { | 
|  | 190 | +            i++; | 
| 180 | 191 |         } | 
| 181 | 192 |     } | 
| 182 | 193 | } | 
0 commit comments