7月算法训练------第八天(前缀和)解题报告
题目类型:前缀和
题目难度:中等
第一题、1894. 找到需要补充粉笔的学生编号
- 题目链接:1894. 找到需要补充粉笔的学生编号
- 思路分析:
先将数组chalk
中的数全加起来得到sum
,用sum
对k取余y
,得到余数y
,然后用y
减去数组chalk
中的每个数,当结果小于0
时,就返回当前索引; - 代码:
class Solution {
public int chalkReplacer(int[] chalk, int k) {
long sum = 0;
for(int i : chalk){
sum += (long)i;
}
long y = k % sum;
if(y == 0){
return 0;
}
long x = y;
for(int i = 0;i < chalk.length; i++){
x = x - (long)chalk[i];
if(x < 0){
return i;
}
}
return 0;
}
}
第二题、2256. 最小平均差
- 题目链接:2256. 最小平均差
- 思路分析:
我们用两个数组存储前i
个和后n-i
个数的和,即frontSum
和backSum
;
然后,我们求的前i
个和后n-i
个数的平均值,即frontMean
和backMean
;
用数组sub
记录他们之间的差值的绝对值,遍历sub
得到其中最小值和最小值的索引,返回这个索引。 - 代码:
class Solution {
public int minimumAverageDifference(int[] nums) {
if(nums.length == 1) return 0;
int n = nums.length;
long[] frontSum = new long[n];
long[] backSum = new long[n];
frontSum[0] = (long)nums[0];
for(int i = 1; i < n; i++){
frontSum[i] = frontSum[i-1] + (long)nums[i];
}
backSum[n - 1] = 0;
backSum[n - 2] = (long)nums[n - 1];
for(int j = n- 3; j >= 0; j--){
backSum[j] = backSum[j+1] + (long)nums[j+1];
}
long[] frontMean = new long[n];
long[] backMean = new long[n];
for(int i = 0; i < n; i++){
frontMean[i] = frontSum[i] / (i + 1);
if(i == n - 1){
backMean[i] = 0;
}else{
backMean[i] = backSum[i] / (n - 1 - i);
}
}
long[] sub = new long[n];
for(int i = 0; i < n; i++){
sub[i] = Math.abs(frontMean[i] - backMean[i]);
}
long min = Long.MAX_VALUE;
for(int i = 0; i < n; i++){
if(sub[i] < min){
min = sub[i];
}
}
for(int i = 0; i < n; i++){
if(sub[i] == min){
return i;
}
}
return 1;
}
}
第三题、1737. 满足三条件之一需改变的最少字符数
- 题目链接:1737. 满足三条件之一需改变的最少字符数
- 思路分析:
我们用minChar(char[] a, char[] b)
方法计算满足条件一和条件二的最小值;
minChar(char[] a, char[] b)
的思路就是:
我们枚举26个小写字母,如果a
中有大于当前枚举字母的字母,就将sum++
;
如果b中有小于当前枚举字母的字母,也让sum++
;
当两个字符串都遍历完之后,更新最小值;
用这种方法,将26个字母都枚举过后,最终的最小值就可以返回了。
int min = Math.min(minChar(arra, arrb), minChar(arrb, arra));
对于代码中的这个minChar(arra, arrb)
,求得满足条件一的最小值;
minChar(arrb, arra)
,求得满足条件二的最小值。
最终将这两个值取最小,就得到条件一和条件二的最小值;
而对于条件三:我们也采用类似的方法,枚举26个字母,记录两个字符串中与枚举字母不相等的字符数量,返回最小值;
将以上两个最小值,再求一次最小,就是结果了。
3. 代码:
class Solution {
public int minCharacters(String a, String b) {
// if(a.equals(b)){
// return 0;
// }
char[] arra = a.toCharArray();
char[] arrb = b.toCharArray();
int min = Math.min(minChar(arra, arrb), minChar(arrb, arra));
// int min = Integer.MAX_VALUE;
for(char c = 'a'; c <= 'z'; c++){
int sum = 0;
for(char ca : arra){
if(ca != c){
sum++;
}
}
for(char cb : arrb){
if(cb != c){
sum++;
}
}
min = Math.min(min, sum);
}
return min;
}
private static int minChar(char[] a, char[] b){
int min = Integer.MAX_VALUE;
for(char c = 'a'; c < 'z'; ++c){
int sum = 0;
for(char ca : a){
if(ca > c){
sum++;
}
}
for(char cb : b){
if(cb <= c){
sum++;
}
}
min = Math.min(min, sum);
}
return min;
}
}
第四题、2055. 蜡烛之间的盘子
- 题目链接:2055. 蜡烛之间的盘子
- 思路分析:
用左右指针遍历,每个qs[i]
中的两个数,l = qs[i][0]
,r = qs[i][1]
,当做右指针都遇到'|'
时,就返回两指针之间‘*’
的数量 - 代码:
class Solution {
public int[] platesBetweenCandles(String s, int[][] qs) {
char[] cs = s.toCharArray();
int n = cs.length, m = qs.length;
int[] l = new int[n], r = new int[n];
int[] sum = new int[n + 1];
for (int i = 0, j = n - 1, p = -1, q = -1; i < n; i++, j--) {
if (cs[i] == '|') p = i;
if (cs[j] == '|') q = j;
l[i] = p; r[j] = q;
sum[i + 1] = sum[i] + (cs[i] == '*' ? 1 : 0);
}
int[] ans = new int[m];
for (int i = 0; i < m; i++) {
int a = qs[i][0], b = qs[i][1];
int c = r[a], d = l[b];
if (c != -1 && c <= d) ans[i] = sum[d + 1] - sum[c];
}
return ans;
}
}