前言
这是七月集训的第八日,今日的训练内容是 前缀和
解题报告
1.力扣1894
原题链接
题目概述
一个班级里有 n 个学生,编号为 0 到 n - 1 。每个学生会依次回答问题,编号为 0 的学生先回答,然后是编号为 1 的学生,以此类推,直到编号为 n - 1 的学生,然后老师会重复这个过程,重新从编号为 0 的学生开始回答问题。
给你一个长度为 n 且下标从 0 开始的整数数组 chalk 和一个整数 k 。一开始粉笔盒里总共有 k 支粉笔。当编号为 i 的学生回答问题时,他会消耗 chalk[i] 支粉笔。如果剩余粉笔数量 严格小于 chalk[i] ,那么学生 i 需要 补充 粉笔。
请你返回需要 补充 粉笔的学生 编号 。
解题思路
首先先将所有的粉笔消耗量全都加起来,然后用 k 对粉笔的消耗量进行取模运算,这样就可以使得在 k 的值一定会小于一次循环的最大消耗量,此时再对消耗量进行累加,什么时候的消耗量大于了现在的 k 就返回现在的下标 i 即可。
源码剖析
int chalkReplacer(int* chalk, int chalkSize, int k){
long sum=0;
int i;
for(i=0;i<chalkSize;++i){
sum+=chalk[i];
}
k%=sum;
sum = 0;
for(i=0;i<chalkSize;i++){
sum+=chalk[i];
if(sum>k){
break;
}
}
return i;
}
2.力扣2256
原题链接
题目概述
给你一个下标从 0 开始长度为 n 的整数数组 nums 。
下标 i 处的 平均差 指的是 nums 中 前 i + 1 个元素平均值和 后 n - i - 1 个元素平均值的 绝对差 。两个平均值都需要 向下取整 到最近的整数。
请你返回产生 最小平均差 的下标。如果有多个下标最小平均差相等,请你返回 最小 的一个下标。
注意:
- 两个数的 绝对差 是两者差的绝对值。
- n 个元素的平均值是 n 个元素之 和 除以(整数除法) n 。
- 0 个元素的平均值视为 0 。
解题思路
我觉得这应该算是一道模拟的题目,首先用前缀和数组记录下前缀和,然后开始按照题目要求来遍历前缀和数组,注意特别处理一下某些特殊情况和循环的边界,总的来说,这个地方还是有点不清不楚的,虽然多试错几次可以写出来,但是边界条件相当的不熟练,还需多练。
源码剖析
int minimumAverageDifference(int* nums, int numsSize){
long* presum=(long*)malloc(sizeof(long)*(numsSize+1));
memset(presum,0,sizeof(presum));
int i;
presum[0]=0;
for(i=1;i<numsSize+1;++i){
presum[i]=nums[i-1]+presum[i-1];
}
int min = INT_MAX;
int ans = 0;
for(i=0;i<numsSize;++i){
if((numsSize-i-1)!=0){
int tmp = abs((presum[i+1]/(i+1))-(presum[numsSize]-presum[i+1])/(numsSize-i-1));
if(tmp<min){
min = tmp;
ans = i;
}
}else{
int tmp = abs(presum[i+1]/(i+1));
if(tmp <min){
min = tmp;
ans = i;
}
}
}
return ans;
}
3.力扣1737
原题链接
题目概述
给你两个字符串 a 和 b ,二者均由小写字母组成。一步操作中,你可以将 a 或 b 中的 任一字符 改变为 任一小写字母 。
操作的最终目标是满足下列三个条件 之一 :
- a 中的 每个字母 在字母表中 严格小于 b 中的 每个字母 。
- b 中的 每个字母 在字母表中 严格小于 a 中的 每个字母 。
- a 和 b 都 由 同一个 字母组成。
返回达成目标所需的 最少 操作数。
解题思路
函数分为两个部分,一个部分用来计算前两种情况的最小操作数,一个用来计算最后一种的。
首先说说后者,首先将所有字母出现次数都填入哈希表,然后遍历哈希表,找到出现了最多次数的字母,然后用所有字母的总数减去出现次数最多的字母个数,就得到了最少的改变次数。
再说说前者,虽然是两种情况,但其实只要修改一下传入参数就可以反过来寻找,因此来说一说这里的实现思路:使用暴力的枚举法,枚举 26 个字母,将 a 串的所有字符都小于等于这个字母的数(需改变数)与 b 串所有字符都大于等于这个字母的数(需改变数)并加和。枚举完所有字母后,自然就直接可以得到,使得 a 中的字符全都严格大于 b 中字母。然后交换传入参数,就可以得到另一种情况的最少操作数。
最后取 3 种情况中最小的数即可,总的来说,这题的思路是暴力枚举。
源码剖析
int change(char *a,char *b,int asize,int bsize){
int ans = INT_MAX;
for(char x = 'a';x<'z';++x){
int sum = 0;
for(int i = 0;i<asize;++i){
sum += (a[i]<=x?0:1);
}
for(int i = 0;i<bsize;++i){
sum += (b[i]>x?0:1);
}
ans = ans<sum?ans:sum;
}
return ans;
}
int minmend(char *a,char *b,int asize,int bsize){
int hash[26]={0};
int i;
int max = 0;
for(i = 0;i<asize;++i){
hash[(a[i]-'a')]++;
}
for(i = 0;i<bsize;++i){
hash[(b[i]-'a')]++;
}
for(i = 0;i<26;++i){
max = max>hash[i]?max:hash[i];
}
return asize+bsize-max;
}
int minCharacters(char * a, char * b){
int asize = strlen(a);
int bsize = strlen(b);
int tmp = change(a,b,asize,bsize)<change(b,a,bsize,asize)?change(a,b,asize,bsize):change(b,a,bsize,asize);
return tmp<minmend(a,b,asize,bsize)?tmp:minmend(a,b,asize,bsize);
}
4.力扣2055
原题链接
题目概述
给你一个长桌子,桌子上盘子和蜡烛排成一列。给你一个下标从 0 开始的字符串 s ,它只包含字符 ‘’ 和 ‘|’ ,其中 '’ 表示一个 盘子 ,‘|’ 表示一支 蜡烛 。
同时给你一个下标从 0 开始的二维整数数组 queries ,其中 queries[i] = [lefti, righti] 表示 子字符串 s[lefti…righti] (包含左右端点的字符)。对于每个查询,你需要找到 子字符串中 在 两支蜡烛之间 的盘子的 数目 。如果一个盘子在 子字符串中 左边和右边 都 至少有一支蜡烛,那么这个盘子满足在 两支蜡烛之间 。
比方说,s = “|||||" ,查询 [3, 8] ,表示的是子字符串 "||**|” 。子字符串中在两支蜡烛之间的盘子数目为 2 ,子字符串中右边两个盘子在它们左边和右边 都 至少有一支蜡烛。
请你返回一个整数数组 answer ,其中 answer[i] 是第 i 个查询的答案。
解题思路
先做记录。
源码剖析