题解:学而思编程 疯狂的科学家
【题目来源】
学而思编程:疯狂的科学家
【题目描述】
Farmer John 的远房亲戚 Ben 是一个疯狂的科学家。通常这会在家庭聚会时造成不小的摩擦,但这偶尔也会带来些好处,尤其是当 Farmer John 发现他正面对一些有关他的奶牛们的独特而不寻常的问题时。
Farmer John 当前正面对一个有关她的奶牛们的独特而不寻常的问题。他最近订购了 \(N\) 头奶牛(\(1≤N≤1000\)),包含两种不同品种:荷斯坦牛和更赛牛。他在订单中用一个长为 \(N\) 的字符串来指定奶牛,其中的字符为 H(表示荷斯坦牛)或 G(表示更赛牛)。不幸的是,当这些奶牛到达他的农场,他给她们排队时,她们的品种组成的字符串与原先的不同。
我们将这两个字符串称为 \(A\) 和 \(B\),其中 \(A\) 是 Farmer John 原先想要的品种字符组成的字符串,\(B\) 是他的奶牛们到达时组成的字符串。Farmer John 并没有简单地检查重新排列 \(B\) 中的奶牛是否能得到 \(A\),而是请他的远房亲戚 Ben 利用他的科学才华来解决这一问题。
经过数月的研究,Ben 发明了一台不同寻常的机器:奶牛品种转换机,能够选择任意奶牛组成的子串并反转她们的品种:在这个子串中的所有 H 变为 G,所有 G 变为 H。Farmer John 想要求出将他当前的序列 \(B\) 变为他本来订购时想要的 \(A\) 需要使用这台机器的最小次数。然而,Ben 的疯狂的科学家技能并不会处理开发奇异机器以外的事,所以你需要帮助 Farmer John 解决这个计算难题。
【输入】
输入的第一行包含 \(N\),以下两行包含字符串 \(A\) 和 \(B\)。每个字符串均包含 \(N\) 个字符,字符均为 H 和 G 之一。
【输出】
输出将 \(B\) 变为 \(A\) 需要使用机器的最小次数。
【输入样例】
7
GHHHGHH
HHGGGHH
【输出样例】
2
【核心思想】
-
问题分析:给定两个长度为 \(N\) 的字符串 \(A\) 和 \(B\)(仅含
H和G),每次操作可选择任意子串并翻转其中所有字符(H变G,G变H)。求将 \(B\) 变为 \(A\) 的最小操作次数。这是一个连续段统计问题,关键在于识别 \(A\) 和 \(B\) 不同的连续段,每段恰好需要一次操作。 -
算法选择:
- 差异段识别:扫描字符串,找出 \(A\) 和 \(B\) 字符不同的连续区间
- 贪心计数:每个不同的连续段恰好需要一次翻转操作,段数即为最小操作次数
-
关键步骤:
- 初始化:读取 \(N\) 和字符串 \(A\)、\(B\)
- 统计不同段数:
cnt = 0:不同段计数flag = 1:标记是否处于"可开始新段"状态- 遍历 \(i\) 从 \(0\) 到 \(N-1\):
- 若
a[i] != b[i]且flag == 1:cnt++:发现新的一段差异flag = 0:标记已进入当前差异段
- 若
a[i] == b[i]:flag = 1:标记可以开始新的差异段
- 若
- 输出
cnt
-
时间/空间复杂度:
- 时间复杂度:\(O(N)\),线性扫描字符串
- 空间复杂度:\(O(1)\),仅需常数变量
-
连续段统计的核心思想:
- 操作覆盖性:一次子串翻转可以覆盖任意连续的差异位置,将一段连续差异全部修正
- 最优性证明:相邻的差异位置若属于同一段,一次操作即可修复;若分开操作则次数更多。因此每段差异恰好对应一次最优操作
- 状态机设计:
flag作为状态机,区分"在差异段内"和"在相同段内",仅在从相同段进入差异段时计数 - 无重叠约束:翻转操作的选择相互独立,不存在重叠或包含的复杂约束,贪心策略即为最优
- 适用于"子串翻转/取反 + 最小操作次数"类问题,连续段识别将问题简化为线性计数
【算法标签】
字符串入门
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; // 字符串长度
string a, b; // 两个字符串
cin >> n >> a >> b; // 读入长度和两个字符串
int cnt = 0, flag = 1; // cnt: 不同段数量,flag: 标记是否在新的一段中
for (int i = 0; i < n; i++) // 遍历每个位置
{
// 如果当前位置字符不同,且flag为1(表示新的一段开始)
if (a[i] != b[i] && flag)
{
cnt++; // 不同段数量加1
flag = 0; // 标记进入当前不同段
}
// 如果当前位置字符相同
if (a[i] == b[i])
{
flag = 1; // 标记可以开始新的不同段
}
}
cout << cnt << endl; // 输出不同段的数量
return 0;
}
【运行结果】
7
GHHHGHH
HHGGGHH
2
浙公网安备 33010602011771号