本文涉及知识点
栈
LeetCode 770. 基本计算器 IV
给定一个表达式如 expression = “e + 8 - a + 5” 和一个求值映射,如 {“e”: 1}(给定的形式为 evalvars = [“e”] 和 evalints = [1]),返回表示简化表达式的标记列表,例如 [“-1a",“14”]
表达式交替使用块和符号,每个块和符号之间有一个空格。
块要么是括号中的表达式,要么是变量,要么是非负整数。
变量是一个由小写字母组成的字符串(不包括数字)。请注意,变量可以是多个字母,并注意变量从不具有像 “2x” 或 “-x” 这样的前导系数或一元运算符 。
表达式按通常顺序进行求值:先是括号,然后求乘法,再计算加法和减法。
例如,expression = “1 + 2 * 3” 的答案是 [“7”]。
输出格式如下:
对于系数非零的每个自变量项,我们按字典排序的顺序将自变量写在一个项中。
例如,我们永远不会写像 “bac” 这样的项,只写 “abc”。
项的次数等于被乘的自变量的数目,并计算重复项。我们先写出答案的最大次数项,用字典顺序打破关系,此时忽略词的前导系数。
例如,"aabc” 的次数为 4。
项的前导系数直接放在左边,用星号将它与变量分隔开(如果存在的话)。前导系数 1 仍然要打印出来。
格式良好的一个示例答案是 [“-2aaa", "3aab”, “3bb”, “4a", "5c”, “-6”] 。
系数为 0 的项(包括常数项)不包括在内。
例如,“0” 的表达式输出为 [] 。
注意:你可以假设给定的表达式均有效。所有中间结果都在区间 [-231, 231 - 1] 内。
示例 1:
输入:expression = “e + 8 - a + 5”, evalvars = [“e”], evalints = [1]
输出:[“-1*a”,“14”]
示例 2:
输入:expression = “e - 8 + temperature - pressure”,
evalvars = [“e”, “temperature”], evalints = [1, 12]
输出:[“-1*pressure”,“5”]
示例 3:
输入:expression = “(e + 8) * (e - 8)”, evalvars = [], evalints = []
输出:[“1ee”,“-64”]
提示:
1 <= expression.length <= 250
expression 由小写英文字母,数字 ‘+’, ‘-’, ‘*’, ‘(’, ‘)’, ’ ’ 组成
expression 不包含任何前空格或后空格
expression 中的所有符号都用一个空格隔开
0 <= evalvars.length <= 100
1 <= evalvars[i].length <= 20
evalvars[i] 由小写英文字母组成
evalints.length == evalvars.length
-100 <= evalints[i] <= 100
栈
变量的值,直接记录在哈希映射,使用时直接查询。除此之外,就是标准的计算器。
数据栈记录数值,操作符栈记录操作符。
遇到右括号或运算结束时才计算加减,此时确保没有乘法。ret = 0; 如果栈顶操作符是+,则ret += 数据栈顶, 否则ret -=数据栈顶。两个栈出栈。直到遇到(或操作栈为空。如果遇到(,则把左括号出栈。栈顶元素 += ret。
乘法执行时机:新的运算数或括号执行完成。 只需要执行一次乘法。
操作数(变量、常量) 之前的符合如果是乘号,马上计算。否则,等右括号或结束时,统一计算。
操作符栈只会有+ - (*。
自定义操作数
CAItem 的 m_vNames记录 单项式的变量名,升序排序。
CAItem的小于如下,长度相等比较字典序,否则长度长的在前。
bool operator<(const CAItem& o)const {
if (m_vNames.size() == o.m_vNames.size()) {
return m_vNames < o.m_vNames;
}
return m_vNames.size() > o.m_vNames.size();
}
CMulItem 记录多项式的值,乘法:快速排序后,合并同类项。加法:归并排序后,合并同类项。
代码
核心代码
struct CAItem
{
CAItem(int num) {
m_iNum = num;
}
CAItem(string strName) {
m_vNames.emplace_back(strName);
m_iNum = 1;
}
bool operator<(const CAItem& o)const {
if (m_vNames.size() == o.m_vNames.size()) {
return m_vNames < o.m_vNames;
}
return m_vNames.size() > o.m_vNames.size();
}
vector<string> m_vNames;
int m_iNum;
};
struct CMulItem
{
CMulItem(int num) {
m_vars.emplace_back(CAItem(num));
}
CMulItem(string strName) {
m_vars.emplace_back(CAItem(strName));
}
CMulItem() {};
CMulItem(const vector< CAItem>& sortItems) {
m_vars.emplace_back(sortItems[0]);
for (int i = 1; i < sortItems.size(); i++) {
if (m_vars.back().m_vNames == sortItems[i].m_vNames) {
m_vars.back().m_iNum += sortItems[i].m_iNum;
}
else {
m_vars.emplace_back(sortItems[i]);
}
}
}
vector< CAItem> m_vars;
CMulItem operator*(const CMulItem& o) const{
vector< CAItem> items;
for (const auto& v1 : m_vars) {
for (const auto& v2 : o.m_vars) {
CAItem cur = v1;
cur.m_vNames.insert(cur.m_vNames.end(), v2.m_vNames.begin(), v2.m_vNames.end());
cur.m_iNum *= v2.m_iNum;
sort(cur.m_vNames.begin(), cur.m_vNames.end());
items.emplace_back(cur);
}
}
sort(items.begin(), items.end());//排序后,方便合并同类项
return CMulItem(items);
}
CMulItem operator+(const CMulItem& o) const {
vector< CAItem> items;
int i1 = 0, i2 = 0;
while ((i1 <m_vars.size()) && (i2 < o.m_vars.size())) {
if (m_vars[i1] < o.m_vars[i2]) {
items.emplace_back(m_vars[i1++]);
}
else {
items.emplace_back(o.m_vars[i2++]);
}
}
items.insert(items.end(), m_vars.begin() + i1, m_vars.end());
items.insert(items.end(), o.m_vars.begin() + i2, o.m_vars.end());
return CMulItem(items);
}
void Plus() {
for (auto& item : m_vars) {
item.m_iNum *= -1;
}
}
};
class Solution {
public:
vector<string> basicCalculatorIV(string exp, vector<string>& evalvars, vector<int>& evalints) {
for (int i = 0; i < evalints.size(); i++) {
m_Var[evalvars[i]] = evalints[i];
}
for (int i = 0; i < exp.length(); i++) {
if (('(' == exp[i]) || ('+' == exp[i]) || ('-' == exp[i]) || ('*' == exp[i])) {
m_staOpe.emplace(exp[i]);
}
else if (isdigit( exp[i])) {
int num = 0;
while (isdigit(exp[i])) {
num = num * 10 + (exp[i] - '0');
i++;
}
i--;
m_staNum.emplace(num);
CalMul();;
}
else if (isalpha(exp[i])) {
string strName;
while (isalpha(exp[i])) {
strName += exp[i++];
}
i--;
if (m_Var.count(strName)) {
m_staNum.emplace(m_Var[strName]);
}
else {
m_staNum.emplace(strName);
}
CalMul();
}
else if (')' == exp[i]) {
Cal();
}
}
Cal();
vector<string> rets;
for (auto it = m_staNum.top().m_vars.begin(); it != m_staNum.top().m_vars.end(); ++it) {
if (0 == it->m_iNum) { continue; }
std::ostringstream os;
os << it->m_iNum;
for (const auto& var : it->m_vNames) {
os << "*" << var;
}
rets.emplace_back(os.str());
}
return rets;
}
void CalMul() {
if (m_staOpe.size() && ('*' == m_staOpe.top())) {
CMulItem mulItem = m_staNum.top();
m_staNum.pop();
m_staNum.top() = m_staNum.top() * mulItem;
m_staOpe.pop();
}
}
void Cal() {
CMulItem items(0);
while (m_staOpe.size() && ('(' != m_staOpe.top())) {
auto num2 = m_staNum.top();
m_staNum.pop();
if ('-' == m_staOpe.top()) {
num2.Plus();
}
m_staOpe.pop();
items = items + num2;
}
m_staNum.top() = m_staNum.top()+ items;
if (m_staOpe.size() && ('(' == m_staOpe.top())) { m_staOpe.pop(); };
CalMul();
}
stack< CMulItem> m_staNum;
stack<char> m_staOpe;
unordered_map<string, int> m_Var;
};
单元测试
template<class T1,class T2>
void AssertEx(const T1& t1, const T2& t2)
{
Assert::AreEqual(t1 , t2);
}
template<class T>
void AssertEx(const vector<T>& v1, const vector<T>& v2)
{
Assert::AreEqual(v1.size(), v2.size());
for (int i = 0; i < v1.size(); i++)
{
Assert::AreEqual(v1[i], v2[i]);
}
}
template<class T>
void AssertV2(vector<vector<T>> vv1, vector<vector<T>> vv2)
{
sort(vv1.begin(), vv1.end());
sort(vv2.begin(), vv2.end());
Assert::AreEqual(vv1.size(), vv2.size());
for (int i = 0; i < vv1.size(); i++)
{
AssertEx(vv1[i], vv2[i]);
}
}
namespace UnitTest
{
string expression;
vector<string> evalvars;
vector<int> evalints;
TEST_CLASS(UnitTest)
{
public:
TEST_METHOD(TestMethod0)
{
expression = "e + 8 - a + 5", evalvars = { "e" }, evalints = { 1 };
auto res = Solution().basicCalculatorIV(expression, evalvars, evalints);
AssertEx({ "-1*a","14" },res);
}
TEST_METHOD(TestMethod1)
{
expression = "e - 8 + temperature - pressure", evalvars = { "e", "temperature" }, evalints = { 1, 12 };
auto res = Solution().basicCalculatorIV(expression, evalvars, evalints);
AssertEx({ "-1*pressure","5" }, res);
}
TEST_METHOD(TestMethod2)
{
expression = "(e + 8) * (e - 8)", evalvars = {}, evalints = {};
auto res = Solution().basicCalculatorIV(expression, evalvars, evalints);
AssertEx({ "1*e*e","-64" }, res);
}
TEST_METHOD(TestMethod3)
{
expression = "3*4", evalvars = {}, evalints = {};
auto res = Solution().basicCalculatorIV(expression, evalvars, evalints);
AssertEx({ "12" }, res);
}
TEST_METHOD(TestMethod4)
{
expression = "2+3*4", evalvars = {}, evalints = {};
auto res = Solution().basicCalculatorIV(expression, evalvars, evalints);
AssertEx({ "14" }, res);
}
TEST_METHOD(TestMethod5)
{
expression = "2+a", evalvars = {}, evalints = {};
auto res = Solution().basicCalculatorIV(expression, evalvars, evalints);
AssertEx({ "1*a","2"}, res);
}
TEST_METHOD(TestMethod6)
{
expression = "2*a", evalvars = {}, evalints = {};
auto res = Solution().basicCalculatorIV(expression, evalvars, evalints);
AssertEx({ "2*a" }, res);
}
TEST_METHOD(TestMethod7)
{
expression = "((a - b) * (b - c) + (c - a)) * ((a - b) + (b - c) * (c - a))", evalvars = {}, evalints = {};
auto res = Solution().basicCalculatorIV(expression, evalvars, evalints);
AssertEx({ "-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" }, res);
}
};
}

扩展阅读
视频课程
有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
相关下载
想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653
| 我想对大家说的话 |
|---|
| 《喜缺全书算法册》以原理、正确性证明、总结为主。 |
| 闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
| 子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
| 如果程序是一条龙,那算法就是他的是睛 |
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

438

被折叠的 条评论
为什么被折叠?



