题目来自:
题目如下:
题目 小红的白色字符串
小红拿到了一个字符串,她准备将一些字母变成白色,变成白色的字母看上去就和空格一样,这样字符串就变成了一些单词。
现在小红希望,每个单词都满足以下两种情况中的一种:
1.开头第一个大写,其余为小写(长度为 1 的大写字母也是合法的)。
2.所有字符全部是小写。
小红想知道,最少需要将多少字母变成白色?
输入
一个仅包含大小写字母的字符串。
字符串长度不超过200000
输出
将字母变成白色的最小数量
写出这道题纯属偶然:由于大写字母前面肯定不能出现字母,所以一旦出现一个非开头的大写字母和前面的字母相连就要删掉该大写字母,这是一种贪心算法。
贪心算法,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解。
这种贪心能得出一种方案,问题在于怎么说明这种方案能使字母变成白色的数量是全局最优解:
我们规定:0为已经被擦去的字母,1为小写字母,2为大写字母。
只考虑如同下面的序列,省略号都是2:
?22.....221
希望能删去尽可能少的字母使得该序列符合题意。
情形1:
如果要保留?,那么第一个2需要变成0,并且后面的2之间互相间隔一个0。
a.如果2的个数为偶数2n,那么序列会变成形如:
?020202....021
这符合题意,删去n个,多删1个都不是该情形下的最优解。
b.如果2的个数为奇数2n+1,那么序列会变成形如:
?020202...0201 或 ?02...2002...021
显然只有这两种大情形,而且你不能再把任何一个0换成2,是该情形下的最优解。此时删去了n+1个。
情形2:
如果删去?。
c.如果2的个数为偶数2n,那么序列会变成形如:
0202020...201 或 02...2002...021 或 002020...21
删去了n+1个,这不是两种情形的最优解,两种情形在2的个数为偶数的情况下最优解为n个。
d.如果2的个数为2n+1,那么序列会变成形如:
02020...2021
删去了n+1个,这是2的个数为偶数的情况下的最优解。
取情形1的a分支和情形2的d分支,就有了开头提到的贪心算法:遇到前面有字符的大写字母就把自己消掉。
题解如下:
#include <bits/stdc++.h>
using namespace std;
vector<int> convert(string ipt){
int len = ipt.size();
vector<int> ret(len);
for(int i=0;i<len;i++){
if('a'<=ipt[i] && ipt[i]<='z') {ret[i]=1;}
else ret[i]=2;
}
return ret;
}
int main() {
string ipt;
cin >> ipt;
vector<int> nums = convert(ipt);
int ans=0;
for(int i=1;i<nums.size();i++){
if(nums[i]==2 && nums[i-1]!=0){
ans++;
nums[i]=0;
}
}
cout << ans;
return 0;
}
感谢你能看到这里。