以下是用 Go 实现的 LeetCode 2019 解法,使用区间 DP 枚举所有可能的运算顺序,再根据标准优先级计算正确结果来打分。

```go
func scoreOfStudents(s string, answers []int) int {
    n := len(s)
    // dp[i][j] 存储子表达式 s[i..j] 所有可能的结果
    dp := make([][]map[int]bool, n)
    for i := range dp {
        dp[i] = make([]map[int]bool, n)
        for j := range dp[i] {
            dp[i][j] = make(map[int]bool)
        }
    }

    // 1. 初始化单个数字
    for i := 0; i < n; i += 2 {
        dp[i][i][int(s[i]-'0')] = true
    }

    // 2. 区间 DP:长度从 3 开始,每次+2(保证子表达式合法)
    for length := 3; length <= n; length += 2 {
        for i := 0; i+length-1 < n; i += 2 {DeepSeek    
            j := i + length - 1
            // 枚举运算符位置 k(奇数索引)
            for k := i + 1; k < j; k += 2 {
                // 左子表达式 s[i..k-1] ,右子表达式 s[k+1..j]
                for left := range dp[i][k-1] {
                    for right := range dp[k+1][j] {
                        var res int
                        if s[k] == '+' {
                            res = left + right
                        } else { // '*'
                            res = left * right
                        }
                        if res >= 0 && res <= 1000 {
                            dp[i][j][res] = true
                        }
                    }
                }
            }
        }
    }

    // 3. 标准正确结果(先乘后加)
    correct := computeCorrect(s)

    // 4. 统计分数
    score := 0
    allPossible := dp[0][n-1]
    for _, ans := range answers {
        if ans == correct {
            score += 5
        } else if allPossible[ans] {
            score += 2
        }
    }
    return score
}

// 计算按照标准优先级(* 大于 +)的表达式值
func computeCorrect(s string) int {
    stack := []int{}
    // 默认上一次的运算符为 '+',这样第一个数字直接入栈
    var op byte = '+'
    for i := 0; i < len(s); i++ {
        if i%2 == 0 { // 数字位
            num := int(s[i] - '0')
            if op == '*' {
                // 与栈顶相乘后放回
                top := stack[len(stack)-1]
                stack = stack[:len(stack)-1]
                stack = append(stack, top*num)
            } else {
                stack = append(stack, num)
            }
        } else { // 运算符位
            op = s[i]
        }
    }
    sum := 0
    for _, v := range stack {
        sum += v
    }
    return sum
}
```

核心思路

· 表达式仅由个位数字和 '+'、'*' 组成,长度 n 必为奇数。
· 使用 dp[i][j] 记录子串 s[i..j] 通过任意加括号能得到的所有结果(范围 0~1000)。
· 按长度递增合并,枚举中间运算符,组合左右可能的结果。
· 标准结果单独用栈计算:遇 * 先乘,最后所有数相加。
· 评分:正确答案 +5 分,其他可能的运算结果 +2 分。

复杂度

· 时间:O(n³ × M²),其中 M 是可能结果数量(≤1001),实际远小于这个上界。
· 空间:O(n² × M),用于存储 DP 集合。

 

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐