京东笔试:大小写最优输入策略的两种解法
在英文的输入中,我们经常会遇到大小写切换的问题,频繁切换大小写会增加我们的按键次数,也会降低我们的打字效率。 众所周知,切换大小写有两种方式,一种是按下"caps locks",也就是大写锁定键,这样一来,之后的输入模式都会被切换。另一种是同时按下shift和需要打印的字母,可以临时切换大小写(算作按下两个键)。
已知初始状态下,打字模式是小写,现在给出需要打印的字符串(区分大小写),请你计算出最少需按键多少次才能打印出来。
输入:
输入第一行仅包含一个正整数n,表示字符串的长度(1<=n<=1000000)
输入第二行包含一个长度为n的字符串,仅包含大小写字母
输出:
输出仅包含一个正整数,即最少的按键次数。
样例输入:
6
AaAAAA
样例输出:
8
方法一:找到状态转移利用动态规划进行解决
方法二:用最直接的想法进行输入模拟以将损失最小化
下面给出代码,关键部分都给出了注释
#include <bits/stdc++.h> using namespace std; // 方法一:动态规划 int DP(int **dp, string s) { size_t sz = s.size(); // 初始化,状态从小写开始 dp[0][0] = isupper(s[0]) ? 2 : 1; dp[1][0] = 2; for (size_t i = 1; i < sz; i++) { if (isupper(s[i])) { dp[0][i] = min(dp[0][i - 1] + 2, dp[1][i - 1] + 2); dp[1][i] = min(dp[0][i - 1] + 2, dp[1][i - 1] + 1); } else { dp[0][i] = min(dp[0][i - 1] + 1, dp[1][i - 1] + 2); dp[1][i] = min(dp[0][i - 1] + 2, dp[1][i - 1] + 2); } } return min(dp[0][sz - 1], dp[1][sz - 1]); } // 方法二:压缩模拟 int compress(string s) { vector<int> vec; vec.push_back(1); for (size_t i = 1; i < s.size(); i++) { // 将连续的大小写压缩计数 if(isupper(s[i]) != isupper(s[i - 1])) vec.push_back(1); else vec[vec.size() - 1]++; } int fp = isupper(s[0]) ? 1 : 0; int flag = 0, cnt = 0; // flag当前键盘大小写状态,cnt记录shift和capslock使用次数 for (size_t i = 0; i < vec.size(); i++) { if (((i + fp) & 1) != (flag & 1)) { // 偶数位置代表小写,奇数位置代表大写 cnt++; if (vec[i] > 1) flag ^= 1; // 同大小写的连续两个及以上则锁定capslock并切换大小写状态 } } vec.clear(); return cnt; } int main() { int n; string s; cin >> n; cin >> s; // 方法一:dp int **dp; dp = new int*[2]; for (int i = 0; i < 2; i++) dp[i] = new int[s.size()]; cout << DP(dp, s) << endl; // 方法二:压缩模拟 cout << compress(s) + s.size() << endl; // shift+capslock使用次数加上字母数 return 0; }#京东##笔试题目#