题目列表
3136. 有效单词
3137. K 周期字符串需要的最少操作次数
3138. 同位字符串连接的最小长度
3139. 使数组中所有元素相等的最小开销
一、有效单词
按照题目要求,统计个数,看是否符合条件即可,代码如下
class Solution {
public:
bool isValid(string word) {
string str = "aeiou";
if(word.size()<3) return false;
bool flag1 = false, flag2 = false;
for(auto e:word){
if(isdigit(e)) continue;
if(isalpha(e)){
if(str.find(tolower(e))==string::npos) flag1 = true;
else flag2 = true;
}else{
return false;
}
}
return flag1&&flag2;
}
};
二、K周期字符串需要的最少操作次数
这题本质就是要将所给字符串分成长度为k的一个个子串,然后找这些子串中出现次数最多的,将其他的子串换成出现次数最多的子串,这样我们的操作次数最少。
这里要能想明白:题目要求我们将字符串变成周期为k的字符串<=>我们将字符串分成长度为k的子串,使得子串相同
代码如下
class Solution {
public:
int minimumOperationsToMakeKPeriodic(string word, int k) {
int n = word.size();
int ans = 0;
unordered_map<string,int>cnt;
for(int i=0;i<n;i+=k){
ans = max(ans,++cnt[word.substr(i,k)]);
}
return n/k - ans;
}
};
三、同位字符串连接的最小长度
这题只要从小到大枚举可以的最小长度即可,可能有人觉得这样做会超时,但是不会,因为我们枚举的数是有条件的,它们得是字符串长度的因子,因为题目的第一句话就说我们要用字符串t和若干个t的同位字符串连接成s,而10^5以内的数的因子个数并不是很多,然后我们只要判断字符串是否能拆分成同位字符串即可,代如下码
class Solution {
public:
int minAnagramLength(string s) {
int n = s.size();
vector<vector<int>>pre(n+1,vector<int>(26));
for(int i=0;i<n;i++){
pre[i+1]=pre[i];
pre[i+1][s[i]-'a']++;
}
for(int i=1;i<=n;i++){// 枚举长度
if(n%i) continue;
// i得是n的因子
bool flag = true;
for(int j=2*i;j<=n;j+=i){
for(int k=0;k<26;k++){
if(pre[i][k]!=pre[j][k]-pre[j-i][k]){
flag = false;
goto end;
}
}
}
end:
if(flag) return i;
}
return -1;
}
};
四、使数组中所有元素相等的最小开销
这题纯纯数学题,两个操作需要我们进行选择,是优先选择操作一,还是优先操作方案二,或者其他选法?
首先,我们肯定能想到如果cost1*2<=cost2,也就是说平均一次+1操作,操作一的开销更少,那么我们肯定选操作一将所有的数增大为数组中的最大值,这样的开销最少。
那么如果cost1*2>cost2呢?也就是说平均一次+1操作,操作二的开销更少,即我们需要优先进行操作二,让所有小于最大值的数尽可能的往最大值靠近,如果无法进行操作二,我们就选择操作一
可能很多人会这么想,但是这样做并不正确,因为如果开销操作二的足够小,操作一的开销足够大,那么我们完全可以将选一个更大的最大值,从而选择在进行多次操作二,以实现所有数字相同
也就是说我们不确定哪一个数作为最大值会最优,所以我们可以枚举最大值。
那么最大值的上界在哪里呢?我们总不能往后一直枚举。在说明这个问题之前,我们先来想想当我们选定一个最大值时,如何尽可能的选择操作二?如下
从上图可知:
1、mx <= s - mx时,花销为s/2*cost2+(s&1)*cost1
2、mx > s - mx时,花销为(s-mx)*cost2+(mx-(s-mx))*cost1=cost2*(s-mx)+cost1*(2mx-s)
其中mx为需要增加到最大值的最大+1次数,s为总共+1次数
那么我们如何确定我们的枚举上界呢?我们知道当我们的枚举上界越大时,需要+1的次数也会更多,从mx 和 s - mx 的不等式来看,mx的增加次数远远小于s - mx的增加次数,也就是说mx<=s-mx会一直保持不变,花销【s/2*cost2+(s&1)*cost1】只会越来越大所以我们枚举到mx <= s - mx时即可
设枚举到x即可,mn=min(nums),mx=max(nums),s为x=mx时,总共+1次数
2*(x - mn) <= s + (x - mx)*n => x >= (n*mx-2*mn-s)/(n-2) 所以x最多为2*mx
代码如下
class Solution {
const int MOD = 1e9+7;
public:
int minCostToEqualizeArray(vector<int>& nums, int c1, int c2) {
int n = nums.size();
long long s = 0;
int mx = ranges::max(nums);
int mn = ranges::min(nums);
for(auto x:nums) s += mx - x;
if(c1*2<=c2) return s*c1%MOD;
long long ans = LLONG_MAX;
for(int x=mx;x<=2*mx;x++){
int d = x - mn;
long long res;
if(d<=s-d) res = s/2*c2+s%2*c1;
else res = (s-d)*c2 +(d*2-s)*c1;
ans=min(ans,res);
s += n;
}
return ans%MOD;
}
};