题目描述:
一个班级里有 n 个学生,编号为 0 到 n - 1 。每个学生会依次回答问题,编号为 0 的学生先回答,然后是编号为 1 的学生,以此类推,直到编号为 n - 1 的学生,然后老师会重复这个过程,重新从编号为 0 的学生开始回答问题。
给你一个长度为 n 且下标从 0 开始的整数数组 chalk 和一个整数 k 。一开始粉笔盒里总共有 k 支粉笔。当编号为 i 的学生回答问题时,他会消耗 chalk[i] 支粉笔。如果剩余粉笔数量 严格小于 chalk[i] ,那么学生 i 需要 补充 粉笔。
请你返回需要 补充 粉笔的学生 编号 。
思路:
先计算一次所有学生需要的粉笔数sum,用k对其取余,这样就可以在一轮遍历中获得结果;
class Solution {
public:
int chalkReplacer(vector<int>& chalk, int k) {
long long sum = 0;
int n = chalk.size();
for (int i = 0; i < n; ++i) {
sum += chalk[i];
}
k %= sum;
sum = 0;
for (int i = 0; i < n; ++i) {
sum += chalk[i];
if (sum > k) {
return i;
}
}
return -1;
}
};
题目描述:
给你一个下标从 0 开始长度为 n 的整数数组 nums 。
下标 i 处的 平均差 指的是 nums 中 前 i + 1 个元素平均值和 后 n - i - 1 个元素平均值的 绝对差 。两个平均值都需要 向下取整 到最近的整数。
请你返回产生 最小平均差 的下标。如果有多个下标最小平均差相等,请你返回 最小 的一个下标。
注意:
两个数的 绝对差 是两者差的绝对值。
n 个元素的平均值是 n 个元素之 和 除以(整数除法) n 。
0 个元素的平均值视为 0 。
思路:
首先特判数组长度为1时,差值为0;
计算一次数组总和sum,然后分步计算部分和partsum,每计算一次部分和partsum,就可以计算前半部分partsum和后半部分sum-partsum的平均值的绝对差;这里就需要一个记录下标mini,和绝对差ans的变量。
注意是可以计算整个数组的平均值的。这里需要特写;
class Solution {
public:
int minimumAverageDifference(vector<int>& nums) {
long long sum = 0;
long long partsum = 0;
int ans = 100000020, mini = -1;
int n = nums.size();
if (n == 1) {
return 0;
}
for (int i = 0; i < n; ++i) {
sum += nums[i];
}
int val = 0;
for (int i = 0; i < n; ++i) {
partsum += nums[i];
if (i != n -1) {
val = abs(partsum/(i+1) - (sum - partsum)/(n-i-1));
} else {
val = sum / n;
}
if (val < ans) {
ans = val;
mini = i;
}
}
return mini;
}
};
题目描述:
给你两个字符串 a 和 b ,二者均由小写字母组成。一步操作中,你可以将 a 或 b 中的 任一字符 改变为 任一小写字母 。
操作的最终目标是满足下列三个条件 之一 :
a 中的 每个字母 在字母表中 严格小于 b 中的 每个字母 。
b 中的 每个字母 在字母表中 严格小于 a 中的 每个字母 。
a 和 b 都 由 同一个 字母组成。
返回达成目标所需的 最少 操作数。
思路:
对于前两种情况是一样的,只需要实现一个函数,然后交换参数就能复用;
对于第三种情况,直接枚举26个英文字母,取最小修改值就是答案了;
而对于前两种情况,只需要枚举一个字母分界点x,然后字符串a全部变成小于x的字符,字符串b全部变成大于x的字符,统计操作次数取最小值即可。
class Solution {
int getminchch (const string &a, const string &b) {
int ans = 1000000000;
for (char x = 'a'; x < 'z'; ++x) {
int sum = 0;
for (int i = 0; i < a.size(); ++i) {
sum += (a[i] <= x ? 0 : 1);
}
for (int i = 0; i < b.size(); ++i) {
sum += (b[i] > x ? 0 : 1);
}
ans = min(ans, sum);
}
return ans;
}
public:
int minCharacters(string a, string b) {
int ret = min(getminchch(a, b), getminchch(b, a));
for (char x = 'a'; x <= 'z'; ++x) {
int sum = 0;
for (int i = 0; i < a.size(); ++i) {
sum += (a[i] == x ? 0 : 1);
}
for (int i = 0; i < b.size(); ++i) {
sum += (b[i] == x ? 0 : 1);
}
ret = min(ret, sum);
}
return ret;
}
};
//重做
题目描述:
给你一个长桌子,桌子上盘子和蜡烛排成一列。给你一个下标从 0 开始的字符串 s ,它只包含字符 '*' 和 '|' ,其中 '*' 表示一个 盘子 ,'|' 表示一支 蜡烛 。
同时给你一个下标从 0 开始的二维整数数组 queries ,其中 queries[i] = [lefti, righti] 表示 子字符串 s[lefti...righti] (包含左右端点的字符)。对于每个查询,你需要找到 子字符串中 在 两支蜡烛之间 的盘子的 数目 。如果一个盘子在 子字符串中 左边和右边 都 至少有一支蜡烛,那么这个盘子满足在 两支蜡烛之间 。
比方说,s = "||**||**|*" ,查询 [3, 8] ,表示的是子字符串 "*||**|" 。子字符串中在两支蜡烛之间的盘子数目为 2 ,子字符串中右边两个盘子在它们左边和右边 都 至少有一支蜡烛。
请你返回一个整数数组 answer ,其中 answer[i] 是第 i 个查询的答案。
思路:
为了方便做前缀和的差分,我们首先可以将字符串的第一个字符填充一下;
用suml表示蜡烛的前缀和,用sump表示盘子的前缀和;
对于每个给定的区间,利用二分查找找到最左边的蜡烛和最右边的蜡烛,然后利用差分计算两者之间的蜡烛数量即可;
class Solution {
int getMinL(int suml[100010], int l, int r) {
int pre = l - 1;
int ans = -1;
while (l <= r) {
int mid = (l + r) >> 1;
if (suml[mid] - suml[pre]) {
r = mid -1;
ans = mid;
} else {
l = mid + 1;
}
}
return ans;
}
int getMaxL(int suml[100010], int l, int r) {
int prer = r;
int ans = -1;
--l;
--r;
while (l <= r) {
int mid = (l + r) >> 1;
if (suml[prer] - suml[mid]) {
l = mid + 1;
ans = mid + 1;
} else {
r = mid - 1;
}
}
return ans;
}
public:
vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
int suml[100010], sump[100010];
vector<int> ans;
suml[0] = sump[0] = 0;
s = "#"+ s;
for (int i = 1; i < s.length(); ++i) {
suml[i] = suml[i-1] + (s[i] == '|' ? 1 : 0);
sump[i] = sump[i-1] + (s[i] == '*' ? 1 : 0);
}
for (int i = 0; i < queries.size(); ++i) {
int l = queries[i][0] + 1;
int r = queries[i][1] + 1;
int ll = getMinL(suml, l, r);
if (ll == -1) {
ans.push_back(0);
} else {
int rr = getMaxL(suml, l, r);
ans.push_back(sump[rr]- sump[ll]);
}
}
return ans;
}
};
//重做