文章目录
- 0. Leetcode [1984. 学生分数的最小差值](https://leetcode-cn.com/problems/minimum-difference-between-highest-and-lowest-of-k-scores/)
- 1. Leetcode [1876. 长度为三且各字符不同的子字符串](https://leetcode-cn.com/problems/substrings-of-size-three-with-distinct-characters/)
- 2. Leetcode [1839. 所有元音按顺序排布的最长子字符串](https://leetcode-cn.com/problems/longest-substring-of-all-vowels-in-order/)
- 3. Leetcode [1052. 爱生气的书店老板](https://leetcode-cn.com/problems/grumpy-bookstore-owner/)
- 总结
0. Leetcode 1984. 学生分数的最小差值
给你一个 下标从 0 开始 的整数数组 nums ,其中 nums[i] 表示第 i 名学生的分数。另给你一个整数 k 。
从数组中选出任意 k 名学生的分数,使这 k 个分数间 最高分 和 最低分 的 差值 达到 最小化 。
返回可能的 最小差值 。
分析与解答
由于选择 k
名学生时没有顺序要求,因此可以先排序,然后选择连续 k
名学生,以此确保每次选择 k
名学生后的最高分与最低分的差值是局部最小。遍历数组,得到全局最小。
class Solution {
public:
int minimumDifference(vector<int>& nums, int k) {
if (k == 1) {
return 0;
}
sort(nums.begin(), nums.end()); // 排序
// 排序后只需计算 i 与 i + k 数的差值
int min(INT_MAX);
for (int i = 0; i < nums.size() - k + 1; ++i) {
int cur = nums[i + k - 1] - nums[i];
if (min > cur) {
min = cur;
}
}
return min;
}
};
排序时间复杂度为 O ( N l o g N ) O(NlogN) O(NlogN),遍历数组时间复杂度为 O ( N ) O(N) O(N),因此算法时间复杂度为 O ( N l o g N ) O(NlogN) O(NlogN)
1. Leetcode 1876. 长度为三且各字符不同的子字符串
如果一个字符串不含有任何重复字符,我们称这个字符串为 好 字符串。
给你一个字符串 s ,请你返回 s 中长度为 3 的 好子字符串 的数量。
注意,如果相同的好子字符串出现多次,每一次都应该被记入答案之中。
子字符串 是一个字符串中连续的字符序列。
分析与解答
对字符串进行搜索,判断是否符合题意即可。
class Solution {
public:
int countGoodSubstrings(string s) {
if (s.size() < 3) {
return 0;
}
int result(0);
int l(0), r(l + 2);
while (r < s.size()) {
// 判断字串是否符合题意
if (s[l] == s[l + 1]) {
l++;
r++;
} else if (s[l + 1] == s[l + 2]) {
l += 2;
r += 2;
} else if (s[l] == s[l + 2]) {
l++;
r++;
} else {
result++;
l++;
r++;
}
}
return result;
}
};
算法需要遍历数组,由于判断是否为 好
字串的时间复杂度为
O
(
1
)
O(1)
O(1),因此算法时间复杂度为
O
(
N
)
O(N)
O(N)
2. Leetcode 1839. 所有元音按顺序排布的最长子字符串
当一个字符串满足如下条件时,我们称它是 美丽的 :
所有 5 个英文元音字母(‘a’ ,‘e’ ,‘i’ ,‘o’ ,‘u’)都必须 至少 出现一次。
这些元音字母的顺序都必须按照 字典序 升序排布(也就是说所有的 ‘a’ 都在 ‘e’ 前面,所有的 ‘e’ 都在 ‘i’ 前面,以此类推)
比方说,字符串 “aeiou” 和 “aaaaaaeiiiioou” 都是 美丽的 ,但是 “uaeio” ,“aeoiu” 和 “aaaeeeooo” 不是美丽的 。
给你一个只包含英文元音字母的字符串 word ,请你返回 word 中 最长美丽子字符串的长度 。如果不存在这样的子字符串,请返回 0 。
子字符串 是字符串中一个连续的字符序列。
分析与解答
由于要找出顺序排列的子字符串,因此遍历字符串,使用两个指针记录符合条件的字串的首位置与尾位置。在当前搜索子串不满足条件时,移动首指针,并重置计数器;若当前子串搜索结束,通过首尾指针计算子串长度,并与当前最大值进行比较。
class Solution {
public:
int longestBeautifulSubstring(string word) {
int l(0), r(0), result(0);
char set[5]{'a', 'e', 'i', 'o', 'u'};
int curIdx(0);
while (r < word.size()) {
if (word[r] != set[curIdx]) { // 当前字符不是期望的字
if (word[r] == 'a') { // 若当前字母为 'a',r 不变
curIdx = 0;
l = r;
} else { // 若当前字母不为 'a',r 向后移
curIdx = 0;
l = r + 1;
r++;
}
} else { // 找到当前元音最后出现位置
while (word[r] == set[curIdx]) {
r++;
}
curIdx = curIdx + 1;
if (curIdx > 4) { // 循环完一个完美字符串
if (result < r - l) {
result = r - l;
}
l = r; // 循环结束移动首指针,否则字符串 aeiouaeiou 判断出错
curIdx = curIdx % 5;
}
}
}
return result;
}
};
算法只需遍历一次数组,因此算法时间复杂度为 O ( N ) O(N) O(N)
3. Leetcode 1052. 爱生气的书店老板
有一个书店老板,他的书店开了 n 分钟。每分钟都有一些顾客进入这家商店。给定一个长度为 n 的整数数组 customers ,其中 customers[i] 是在第 i 分钟开始时进入商店的顾客数量,所有这些顾客在第 i 分钟结束后离开。
在某些时候,书店老板会生气。 如果书店老板在第 i 分钟生气,那么 grumpy[i] = 1,否则 grumpy[i] = 0。
当书店老板生气时,那一分钟的顾客就会不满意,若老板不生气则顾客是满意的。
书店老板知道一个秘密技巧,能抑制自己的情绪,可以让自己连续 minutes 分钟不生气,但却只能使用一次。
请你返回 这一天营业下来,最多有多少客户能够感到满意 。
分析与解答
首先按照默认情况计算满意顾客数量,之后以 minutes
为窗口长度,遍历 grumpy
,将原本为 1
(即生气)时的顾客人数加到基础满意顾客数量上,并与最佳满意顾客数量比较更新。
class Solution {
public:
int maxSatisfied(vector<int>& customers, vector<int>& grumpy, int minutes) {
int sun(0); // 正常情况下满意顾客数量
int result(0);
for (int i = 0; i < grumpy.size(); ++i) {
if (grumpy[i] == 0) {
sun += customers[i];
}
}
result = sun; // 最差情况下结果
for (int i = 0; i < grumpy.size() - minutes + 1; ++i) {
int curR(sun);
for (int j = 0; j < minutes; j++) { // 可能的增量
if (grumpy[i + j] == 1) {
curR += customers[i + j];
}
}
if (curR > result) { // 更新最佳答案
result = curR;
}
}
return result;
}
};
算法需要遍历两次数组,因此算法时间复杂度为 O ( N ) O(N) O(N)
总结
滑动窗口与双指针很相像,但是窗口通常是搜索固定长度,即两个指针位置是相关的,而双指针中两个指针都很自由,通常通过判断是否满足条件决定移动方向与步长。