LeetCode 2019. 解出数学表达式的学生分数

本文介绍了一种针对学生计算特定格式数学表达式的评分算法。该算法首先计算表达式的标准答案,然后评估每个学生的答案,根据答案的正确性和运算顺序给予相应的分数。文章详细解释了如何使用动态规划来找出所有可能的运算顺序及其结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给你一个字符串 s ,它 只 包含数字 0-9 ,加法运算符 '+' 和乘法运算符 '*' ,这个字符串表示一个 合法 的只含有 个位数数字 的数学表达式(比方说 3+5*2)。有 n 位小学生将计算这个数学表达式,并遵循如下 运算顺序 :

按照 从左到右 的顺序计算 乘法 ,然后
按照 从左到右 的顺序计算 加法 。
给你一个长度为 n 的整数数组 answers ,表示每位学生提交的答案。你的任务是给 answer 数组按照如下 规则 打分:

如果一位学生的答案 等于 表达式的正确结果,这位学生将得到 5 分。
否则,如果答案由 一处或多处错误的运算顺序 计算得到,那么这位学生能得到 2 分。
否则,这位学生将得到 0 分。
请你返回所有学生的分数和。

示例 1:

输入:s = "7+3*1*2", answers = [20,13,42]
输出:7
解释:如上图所示,正确答案为 13 ,因此有一位学生得分为 5 分:[20,13,42] 。
一位学生可能通过错误的运算顺序得到结果 20 :7+3=10,10*1=10,10*2=20 。所以这位学生得分为 2 分:[20,13,42] 。
所有学生得分分别为:[2,5,0] 。所有得分之和为 2+5+0=7 。
示例 2:

输入:s = "3+5*2", answers = [13,0,10,13,13,16,16]
输出:19
解释:表达式的正确结果为 13 ,所以有 3 位学生得到 5 分:[13,0,10,13,13,16,16] 。
学生可能通过错误的运算顺序得到结果 16 :3+5=8,8*2=16 。所以两位学生得到 2 分:[13,0,10,13,13,16,16] 。
所有学生得分分别为:[5,0,0,5,5,2,2] 。所有得分之和为 5+0+0+5+5+2+2=19 。
示例 3:

输入:s = "6+0*1", answers = [12,9,6,4,8,6]
输出:10
解释:表达式的正确结果为 6 。
如果一位学生通过错误的运算顺序计算该表达式,结果仍为 6 。
根据打分规则,运算顺序错误的学生也将得到 5 分(因为他们仍然得到了正确的结果),而不是 2 分。
所有学生得分分别为:[0,0,5,0,0,5] 。所有得分之和为 10 分。
 

提示:

3 <= s.length <= 31
s 表示一个只包含 0-9 ,'+' 和 '*' 的合法表达式。
表达式中所有整数运算数字都在闭区间 [0, 9] 以内。
1 <= 数学表达式中所有运算符数目('+' 和 '*') <= 15
测试数据保证正确表达式结果在范围 [0, 1000] 以内。
n == answers.length
1 <= n <= 104
0 <= answers[i] <= 1000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/the-score-of-students-solving-math-expression
 

解法:

区间dp。我是真没想到用dp做,主要是没想到运算顺序进行组合的方式。dp[i][j]表示i到j的所有不同运算顺序的组合值。那么dp[i][j]=dp[i][k-1]Odp[k+1][j],i<k<j,O表示下标k所在的‘+’或‘×’运算符。即dp[i][k-1]中所有值与dp[k+1][j]中所有值进行组合的到所有的dp[i][j].

class Solution {

	int getAnsST(string &s)
	{
		int stAns = 0;
		stack<int> numSt;
		int countAdd = 0;
		int len = s.length();
		for (int i = 0; i < len; i++)
		{
			if (s[i] >= '0'&&s[i] <= '9')
				numSt.push(s[i] - '0');
			else if (s[i] == '*')
			{
				int val = numSt.top();
				numSt.pop();
				numSt.push(val*(s[i + 1] - '0'));
                ++i;
			}
		}
		int ans = numSt.top();
		numSt.pop();
		while (!numSt.empty())
		{
			ans += numSt.top();
			numSt.pop();
		}
		return ans;
	}

public:
	int scoreOfStudents(string s, vector<int>& answers) {
		int stAns = getAnsST(s);
		vector<int> count(1001);
		for (auto answer : answers)
			++count[answer];
		int ans = 5 * count[stAns];
		int len = s.length();
		vector<vector<unordered_set<int>>> dp(len, vector<unordered_set<int>>(len));
		for (int i = 0; i < len; i += 2)
			dp[i][i] .insert(s[i] - '0');
		for (int i = len - 1; i >=0; i -= 2)
		{
			for (int j = i + 2; j < len; j += 2)
			{
				for (int k = i + 1; k < j; k += 2)
				{
					for (auto num1 : dp[i][k - 1])
					{
						for (auto num2 : dp[k + 1][j])
						{
							int val = 0;
							if (s[k] == '+')
								 val= num1 + num2;
							else
								val = num1 * num2;
							if (val <= 1000)
								dp[i][j].insert(val);
						}
					}
				}
			}
		}
		for (auto num : dp[0][len - 1])
			if (num!=stAns)
				ans += 2 * count[num];
		return ans;
	}
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值