链接:https://www.nowcoder.com/questionTerminal/56ab932abac44c8aabf0af75f598a0b4
来源:牛客网
牛牛有一些排成一行的正方形。每个正方形已经被染成红色或者绿色。牛牛现在可以选择任意一个正方形然后用这两种颜色的任意一种进行染色,这个正方形的颜色将会被覆盖。牛牛的目标是在完成染色之后,每个红色R都比每个绿色G距离最左侧近。牛牛想知道他最少需要涂染几个正方形。
如样例所示: s = RGRGR
我们涂染之后变成RRRGG满足要求了,涂染的个数为2,没有比这个更好的涂染方案。
输入描述:输入包括一个字符串s,字符串s长度length(1 ≤ length ≤ 50),其中只包括'R'或者'G',分别表示红色和绿色。
输出描述:输出一个整数,表示牛牛最少需要涂染的正方形数量
示例1
输入 RGRGR
输出 2
刚看到这个题的时候觉得就是想的模拟,把所有的R放在最右边,所有的G房子最左边,并且我感觉题还误导了,如样例所示: s = RGRGR 我们涂染之后变成RRRGG满足要求了,涂染的个数为2,没有比这个更好的涂染方案。
但其实他还可以直接全涂成R 或 G的情况,只要涂得次数最少即可,比如 GGGGRRR 输出应该为 GGGGGGG
网上的好多博客都没说这一点
明白了这点就好做了,直接扫每一位的左边G的个数与R的个数取最小即可
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
int main(){
char s[100];
scanf("%s",s);
int minn=inf;
int n=strlen(s);
for(int i=0;i<n;i++){
int cnt=0;
for(int j=0;j<i;j++){
if(s[j]!='R')
cnt++;
}
for(int j=i;j<n;j++) {
if(s[j]!='G')
cnt++;
}
minn=min(minn,cnt);
}
printf("%d\n",minn);
}
但是看题解的时候看见一大佬写的前缀和优化,直接变成O(1)的算法
前缀和学习传送门:https://blog.youkuaiyun.com/qq_37236745/article/details/81635319
大佬的写法:
for (int i = 1; i <= n; i++)
G[i] = G[i - 1] + (str[i - 1] == 'G');
for (int i = n; i > 0; i--)
R[i] = R[i + 1] + (str[i - 1] == 'R');
int ans = n;
for (int i = 0; i <= n; i++)
ans = min(ans, G[i] + R[i + 1]);
前缀和就是把从(i,j)间的数的和求出来存起来 然后每次用的时候 比如求 (3-6)的区间和 直接用 sum(6)-sum(3)即可,O(1)复杂度。而这道题优化也就是在求左边G和右边R的时候用到了该思想。