题意就是每组给一个字符串,问你打出这个字符串需要敲多少次键盘要求打完后CapsLock保持关闭.(注意按一次Shift只能输入一个字母,同时在CapsLock开启时使用Shift能输入小写字母).
这题可以直接将连续的(大小写相同的)字母根据长度分为长度为1和长度为1以上的来处理,一遍遍历后得出结果(复杂度O(n)),当然也可以使用DP来做.
这里给出DP的做法.
对于每一个字符,针对输入前后CapsLock开启关闭状态分类
- 若输入后CapsLock关闭
假如输入前关闭,则要么直接输入(小写字母),要么用Shift+当前字母输入(大写字母)
假如输入前开启,要么先输入当前字母再按CapsLock(当前字母是大写的),要么先按CapsLock再输入字母(当前字母小写),都是按两次 - 若输入后CapsLock开启
假如输入前开启,则要么直接输入(大写字母),要么用Shift+当前字母输入(小写字母)
假如输入前关闭,要么先输入当前字母再按CapsLock(当前字母是小写的),要么先按CapsLock再输入字母(当前字母大写),都是按两次
由此可以得出状态转移方程
我们用DP[i][0]来代表输入第i个字母后且CapsLock关闭的情况下需要的最少次数,用DP[i][1]来代表输入第i个字母后且CapsLock开启的情况下需要的最少次数,并定义函数int Upcheck(char ch)
,若ch为大写字母,则返回1,否则返回0,则有
dp[i][0]=min(dp[i-1][0]+Upcheck(s[i])+1,dp[i-1][1]+2)
dp[i][1]=min(dp[i-1][0]+2,dp[i-1][1]+2-Upcheck(s[i]))
特殊的,当i==0时
dp[0][0]=Upcheck(s[i])+1
dp[0][1]=2
下面给出我的代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string.h>
#include <string>
using namespace std;
int Upcheck(char ch)
{
if(ch >= 'A' && ch <= 'Z')
return 1;
return 0;
}
char str[11000];
int dp[11000][2];
int main()
{
int T;
scanf("%d", &T);
getchar();
while(T--)
{
scanf("%s", str);
string s(str);
//===============
//dp[i][0]=min(dp[i-1][0]+Upcheck(s[i])+1,dp[i-1][1]+2);
//dp[i][1]=min(dp[i-1][0]+2,dp[i-1][1]+2-Upcheck(s[i]));
int len = s.length();
for (int i=0;i<len;i++ )
{
if (i==0)
{
dp[i][0]=Upcheck(s[i])+1;
dp[i][1]=2;
}
else
{
dp[i][0]=min(dp[i-1][0]+Upcheck(s[i])+1,dp[i-1][1]+2);
dp[i][1]=min(dp[i-1][0]+2,dp[i-1][1]+2-Upcheck(s[i]));
}
}
printf("%d\n",dp[len-1][0]);
}
return 0;
}