题目描述
难度分:1300
输入n(1≤n≤106)和两个长为n的01
字符串s和t。
有两种操作,每种操作都可以执行任意次。
1. 交换s[i]和s[j],代价为|i−j|。
2. 翻转s[i],即0
变为1
,1
变为0
,代价为1
。
输出把s变成t的最小总代价。
输入样例1
3
100
001
输出样例1
2
输入样例2
4
0101
0011
输出样例2
1
算法
贪心
一开始感觉是DP
,写了一下记忆化搜索发现只有一种策略,于是转为贪心。对于某个满足s[i]≠t[i]的位置i,分为以下两种情况:
- 如果s[i+1]≠t[i+1]且交换s[i]和s[i+1]后能够使得子串s[i:i+1]=t[i:i+1],那就选择交换策略,这样可以一次操作解决两个位置。
- 否则就选择直接改,因为即使存在一个可以交换的其他位置j,交换这两个位置的代价|j−i|≥2,也并不会比直接改这两个位置的数字好。
复杂度分析
时间复杂度
遍历一遍字符串s就可以计算出答案,时间复杂度为O(n)。
空间复杂度
除了输入的两个字符串,仅使用了有限几个变量,额外空间复杂度为O(1)。
C++ 代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
int n;
char s[N], t[N];
int main() {
scanf("%d", &n);
scanf("%s", s + 1);
scanf("%s", t + 1);
int ans = 0;
for(int i = 1; i <= n; i++) {
if(s[i] != t[i]) {
if(i < n && (s[i] == t[i + 1] && s[i + 1] == t[i])) {
ans++;
swap(s[i], s[i + 1]);
}else {
ans++;
s[i] = t[i];
}
}
}
printf("%d\n", ans);
return 0;
}