T1:得到k个黑块的最少涂色次数
给你一个长度为 n 下标从 0 开始的字符串 blocks ,blocks[i] 要么是 ‘W’ 要么是 ‘B’ ,表示第 i 块的颜色。字符 ‘W’ 和 ‘B’ 分别表示白色和黑色。
给你一个整数 k ,表示想要 连续 黑色块的数目。
每一次操作中,你可以选择一个白色块将它 涂成 黑色块。
请你返回至少出现 一次 连续 k 个黑色块的 最少 操作次数。
这个题目的思路就类似于一个定长滑动窗口,固定窗口大小,然后不断向数组右侧滑动,并统计窗口内白色块的数量,记录最小值。
class Solution {
public:
int minimumRecolors(string blocks, int k) {
int n = blocks.size();
int l = 0 ;
int count = 0 ;
int res = 100;
while(l <= n - k ){
for(int i = l ; i < k +l ; i++){
if(blocks[i] == 'W') count ++;
}
res = min(res ,count);
count = 0 ;
l ++;
}
return res;
}
};
T2:二进制字符串重新安排需要的时间
给你一个二进制字符串 s 。在一秒之中,所有 子字符串 “01” 同时 被替换成 “10” 。这个过程持续进行到没有 “01” 存在。
请你返回完成这个过程所需要的秒数。
这个题目在比赛的时候看了很久也没有找到具体思路,也尝试了很多方法,但是一直没有想到用动态规划。而且觉得这个变来变去的也有点复杂。
看了别人的题解过后,可能也没有很理解,但是也摸清楚了一些思路。
因为最终的目的是没有01出现,要达到这一目的就需要从数组的开头开始一步一步移动(虽然每次变得都是整体,但是前面的满足条件了就不会再变)所以就用动态规划的思路,这样可以知道在每一个元素的位置达到目标需要的时间,将整体的问题细化,这样更加清晰明了。
class Solution {
public:
int secondsToRemoveOccurrences(string s) {
int n = s.size();
vector<int> f(n);
int sum0 = (s[0] == '0');
for (int i = 1; i < n; i++) {
if (s[i] == '0') {
f[i] = f[i - 1];
sum0++;
} else if (sum0 > 0) {
f[i] = max(f[i - 1] + 1, sum0);
}
}
return f[n - 1];
}
};
307:
T1:赢得比赛需要的最少训练时长
你正在参加一场比赛,给你两个 正 整数 initialEnergy 和 initialExperience 分别表示你的初始精力和初始经验。
另给你两个下标从 0 开始的整数数组 energy 和 experience,长度均为 n 。
你将会 依次 对上 n 个对手。第 i 个对手的精力和经验分别用 energy[i] 和 experience[i] 表示。当你对上对手时,需要在经验和精力上都 严格 超过对手才能击败他们,然后在可能的情况下继续对上下一个对手。
击败第 i 个对手会使你的经验 增加 experience[i],但会将你的精力 减少 energy[i] 。
在开始比赛前,你可以训练几个小时。每训练一个小时,你可以选择将增加经验增加 1 或者 将精力增加 1 。
返回击败全部 n 个对手需要训练的 最少 小时数目。
这个题目的重点其实在满足experience的条件,energy只要一开始满足需求和就好了。但是experience在比赛过程中累加,所以这个最少时间就不是很好把控。在比赛的时候报错了两次,主要是因为我在遍历过程中忘记了是一开始训练达到满足条件再参加比赛,所以在遍历的时候盲目满足大于的条件,盲目加一。
其实最主要的思路就还是模拟。
class Solution {
public:
int minNumberOfHours(int initialEnergy, int initialExperience, vector<int>& energy, vector<int>& experience) {
int sum = 0;
for(auto& a : energy) sum +=a;
int res = 0;
if(sum >= initialEnergy)res += sum -initialEnergy+1;
for(auto& c: experience){
if(initialExperience <= c){
int tmp = c - initialExperience +1;
initialExperience +=tmp + c;
res += tmp;
}
else initialExperience += c;
}
return res;
}
};
T2:最大回文数字
给你一个仅由数字(0 - 9)组成的字符串 num 。
请你找出能够使用 num 中数字形成的 最大回文 整数,并以字符串形式返回。该整数不含 前导零 。
注意:
你 无需 使用 num 中的所有数字,但你必须使用 至少 一个数字。
数字可以重新排序。
回文数就是正读反读都一样的数。所以在回文数中最多只能有一个数出现奇数次。
这个题目的思路就是统计字符串中数字出现的次数,然后按照从大到小的顺序遍历,将大的尽可能放到两边,然后最中间放剩余的字符串。
class Solution {
public:
string largestPalindromic(string num) {
int cnt[10] = {0};
for (auto &ch : num) { // 统计每个数字出现的次数 */
cnt[ch - '0']++;
}
string ans;
for (int i = 9; i >= 0; i--) {
if (i == 0 && ans.size() == 0) { // 0之前没有更大数据, 不放前导0 */
break;
}
int len = cnt[i] / 2;
for (int j = 0; j < len; j++) { // 拆成偶数, 防止在字符串前后 */
ans.push_back(i + '0');
}
cnt[i] %= 2;
}
string res = ans; /* 镜像字符串 */
reverse(res.begin(), res.end());
for (int i = 9; i >= 0; i--) { // 中间再防止一个数字 */
if (cnt[i] > 0) {
ans.push_back(i + '0');
break;
}
}
return ans + res;
}
};