题解:学而思编程 最小结果
【题目来源】
学而思编程:最小结果
【题目描述】
给定一个字符串 \(str\),保证字符串由 \(a(a>1)\) 个数字字符和 \(1\) 个字符'+'组成。
现在你可以向字符串 \(str\) 中添加一对括号:
- 左括号必须添加在'+'的左侧;
- 右括号必须添加在'+'的右侧;
假设左括号左边的数字从左到右组成的整数为 \(p\),左括号与'+'之间的数字从左到右组成的整数为 \(q\),'+'与右括号之间的数字从左到右组成的整数为 \(r\),右括号右边的数字从左到右组成的整数为 \(s\)。
请你安排左括号和右括号的位置,使得 \(p * (q + r) * s\) 最小,并输出这个最小值。
注意,如果左括号在字符串最左侧,认为 \(p=1\),类似的,如果右括号在字符串最右侧,认为 \(s=1\),则'+'两边必须存在数字。
【输入】
一行一个字符串 \(str\),保证'+'的位置合法。
【输出】
一行一个整数,表示 \(p * (q + r) * s\) 的最小值。
【输入样例】
12+34
【输出样例】
20
【核心思想】
-
问题分析:给定由数字和单个
+组成的字符串,在+左右两侧各选一个位置插入括号,将字符串分割为四部分 \(p, q, r, s\),使得 \(p \times (q + r) \times s\) 最小。其中 \(p\) 和 \(s\) 可以为空(此时值为 \(1\)),\(q\) 和 \(r\) 必须非空。这是一个枚举 + 字符串解析问题,核心在于确定分割点的合法范围并遍历所有可能。 -
算法选择:
- 枚举分割点:左括号位置 \(i\) 在
+左侧遍历,右括号位置 \(j\) 在+右侧遍历,枚举所有 \(O(n^2)\) 种分割方案 - 字符串转整数:利用
substr和stoi将子串解析为整数,处理前导零和边界情况
- 枚举分割点:左括号位置 \(i\) 在
-
关键步骤:
- 定位加号:找到
+在字符串中的位置 \(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\)
- 定位加号:找到
-
时间/空间复杂度:
- 时间复杂度:\(O(n^2 \cdot L)\),其中 \(n\) 为字符串长度,\(L\) 为数字位数(
stoi的复杂度),由于数字字符总数固定且较少,实际为 \(O(n^2)\) - 空间复杂度:\(O(1)\),仅使用常数额外空间
- 时间复杂度:\(O(n^2 \cdot L)\),其中 \(n\) 为字符串长度,\(L\) 为数字位数(
-
枚举与字符串解析的核心思想:
- 合法分割点约束:左括号必须在
+左侧(\(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 - i和j - 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
浙公网安备 33010602011771号