题解:学而思编程 最小结果

【题目来源】

学而思编程:最小结果

【题目描述】

给定一个字符串 \(str\),保证字符串由 \(a(a>1)\) 个数字字符和 \(1\) 个字符'+'组成。

现在你可以向字符串 \(str\) 中添加一对括号:

  1. 左括号必须添加在'+'的左侧;
  2. 右括号必须添加在'+'的右侧;

假设左括号左边的数字从左到右组成的整数为 \(p\),左括号与'+'之间的数字从左到右组成的整数为 \(q\),'+'与右括号之间的数字从左到右组成的整数为 \(r\),右括号右边的数字从左到右组成的整数为 \(s\)

请你安排左括号和右括号的位置,使得 \(p * (q + r) * s\) 最小,并输出这个最小值。

注意,如果左括号在字符串最左侧,认为 \(p=1\),类似的,如果右括号在字符串最右侧,认为 \(s=1\),则'+'两边必须存在数字。

【输入】

一行一个字符串 \(str\),保证'+'的位置合法。

【输出】

一行一个整数,表示 \(p * (q + r) * s\) 的最小值。

【输入样例】

12+34

【输出样例】

20

【核心思想】

  1. 问题分析:给定由数字和单个 + 组成的字符串,在 + 左右两侧各选一个位置插入括号,将字符串分割为四部分 \(p, q, r, s\),使得 \(p \times (q + r) \times s\) 最小。其中 \(p\)\(s\) 可以为空(此时值为 \(1\)),\(q\)\(r\) 必须非空。这是一个枚举 + 字符串解析问题,核心在于确定分割点的合法范围并遍历所有可能。

  2. 算法选择

    • 枚举分割点:左括号位置 \(i\)+ 左侧遍历,右括号位置 \(j\)+ 右侧遍历,枚举所有 \(O(n^2)\) 种分割方案
    • 字符串转整数:利用 substrstoi 将子串解析为整数,处理前导零和边界情况
  3. 关键步骤

    • 定位加号:找到 + 在字符串中的位置 \(mid\)
    • 枚举左括号位置\(i\)\(0\)\(mid-1\)):
      • \(p\)\(s[0..i-1]\) 组成的整数,若 \(i=0\)\(p=1\)
      • \(q\)\(s[i..mid-1]\) 组成的整数
    • 枚举右括号位置\(j\)\(mid+1\)\(n-1\)):
      • \(r\)\(s[mid+1..j]\) 组成的整数
      • \(s\)\(s[j+1..n-1]\) 组成的整数,若 \(j=n-1\)\(s=1\)
    • 计算并更新最小值\(result = p \times (q + r) \times s\),维护全局最小值 \(best\)
    • 输出结果\(best\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n^2 \cdot L)\),其中 \(n\) 为字符串长度,\(L\) 为数字位数(stoi 的复杂度),由于数字字符总数固定且较少,实际为 \(O(n^2)\)
    • 空间复杂度:\(O(1)\),仅使用常数额外空间
  5. 枚举与字符串解析的核心思想

    • 合法分割点约束:左括号必须在 + 左侧(\(i \in [0, mid-1]\)),右括号必须在 + 右侧(\(j \in [mid+1, n-1]\)),\(q\)\(r\) 必须包含至少一个数字字符
    • 边界值处理:当左括号在最左侧(\(i=0\))时 \(p=1\),右括号在最右侧(\(j=n-1\))时 \(s=1\),通过条件判断避免空串转整数的错误
    • 全枚举保证最优:由于分割点数量有限(最多 \(O(n^2)\) 种),直接枚举所有合法方案即可找到全局最小值,无需复杂优化
    • 子串解析技巧:利用 substr(pos, len) 配合 stoi 将字符串片段转为整数,注意长度计算为 mid - ij - mid
    • 适用于字符串分割、括号插入位置枚举类问题,特别是搜索空间较小、可以直接暴力枚举的场景

【算法标签】

字符串入门

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int main()
{
    string s;
    cin >> s;  // 输入表达式字符串
    int n = s.size();  // 字符串长度
    int mid = s.find('+');  // 找到加号的位置

    int best = 2e9;  // 初始化为一个大数

    // 遍历所有可能的分割方式
    for (int i = 0; i < mid; i++)  // 第一个分割点(乘号)在加号左边
    {
        for (int j = mid + 1; j < n; j++)  // 第二个分割点(乘号)在加号右边
        {
            // 解析四个数字
            int a = (i == 0 ? 1 : stoi(s.substr(0, i)));  // 第一个乘数
            int b = stoi(s.substr(i, mid - i));  // 加号左边的第二个乘数
            int c = stoi(s.substr(mid + 1, j - mid));  // 加号右边的第一个乘数
            int d = (j == n - 1 ? 1 : stoi(s.substr(j + 1, n - j - 1)));  // 最后一个乘数

            // 计算表达式结果:a * (b + c) * d
            int result = a * (b + c) * d;

            // 更新最小值
            if (result <= best)
                best = result;
        }
    }

    cout << best;  // 输出最小值
    return 0;
}

【运行结果】

12+34
20
posted @ 2026-07-06 21:07  团爸讲算法  阅读(9)  评论(0)    收藏  举报