六月集训(第06天)—滑动窗口
滑动窗口
1. 1984. 学生分数的最小差值
思路:
对成绩升序排列,利用一个长度为k的窗口在数组上滑动,最小差值就是窗口右侧值减去窗口左侧值得最小值。
class Solution {
public:
int minimumDifference(vector<int>& nums, int k) {
int nums_size = nums.size(), i;
int l = 0, r = k - 1;
int ans = 1e5 + 10;
sort(nums.begin(), nums.end());
while (r < nums_size) {
int diff = nums[r++] - nums[l++];
if (diff < ans) ans = diff;
}
return ans;
}
};
2. 1763. 最长的美好子字符串
思路:
我的思路不好,直接暴力枚举不同长度的子字符串。
class Solution {
public:
string longestNiceSubstring(string s) {
int s_len = s.length();
if (s_len < 2) return "";
int i, j;
string ans = "";
int ans_len = 0;
int flag[26][2];
int flag_sub = 0;
for (int sub_len = 2; sub_len <= s_len; ++sub_len) { /* 枚举美好子字符串的长度 */
for (i = 0; i <= s_len - sub_len; ++i) { /* 枚举美好子字符串的起始位置 */
flag_sub = 0;
string sub_s = "";
memset(flag, 0, sizeof(flag));
for (j = i; j - i + 1 <= sub_len; ++j) { /* 从起始位置i遍历长为sub_len的子字符串的长度 */
if (s[j] >= 'a' && s[j] <= 'z') flag[s[j] - 'a'][0] = 1;
else if (s[j] >= 'A' && s[j] <= 'Z') flag[s[j] - 'A'][1] = 1;
sub_s += s[j];
}
for (j = 0; j < 26; ++j) { /* 判断是否是美好子字符串 */
if ( (flag[j][0] ^ flag[j][1]) ) { /* 不是美好子字符串 */
flag_sub = 1;
}
}
if (!flag_sub) { /* 是美好字串 */
if (sub_len > ans_len) {
ans_len = sub_len;
ans.clear();
ans = sub_s;
}
}
}
}
return ans;
}
};
3. 2269. 找到一个数字的 K 美丽值
思路:
滑动窗口的长度为k,遍历每个长为k的字串,字串对应的数字不为0,且能整除num时答案+1。
class Solution {
public:
int divisorSubstrings(int num, int k) {
string nums = to_string(num);
int nums_size = nums.length(), i;
int sub_num = 0, cnt = 0;
for (i = 0; i + k - 1< nums_size; ++i) {
sub_num = 0;
int sub_len = k;
while (sub_len) {
sub_num = sub_num * 10 + (nums[i + k - sub_len] - '0');
--sub_len;
}
if (sub_num && num % sub_num == 0) ++cnt;
}
return cnt;
}
};
4. 995. K 连续位的最小翻转次数
数据范围:
1 <= nums.length <= 105
1 <= k <= nums.length
思路:
题意要求翻转连续的k个数组元素,使得数组所有元素都为1,返回最少的翻转次数,无法实现则返回-1。
遇到一个0就将该位置及其后的k-1个位置的值翻转。如果最后k-1个值不用再翻转了,则得到了最小的翻转次数,否则无法实现翻转。但是样的时间复杂度为$O(n*k)$最坏情况下为$O(n^2)$TLE(超时了)。
优化一下,不用将每个值真的进行翻转,只需要记录每个位置的翻转次数即可,翻转偶数次视为没有翻转,翻转奇数次视为翻转一次。
1) 利用一个队列来记录每个位置翻转次数,每个入队的翻转标记有效时长为 k ,即每个标记到达位置k + q.front() - 1时还有效。
2) 每个位置的值 = 其原始值 ^ 是否翻转,即(q.size() % 2) ^ nums[i]。
3) 当队中的翻转标记过期时k + q.front() - 1 < i,将标记出队。
class Solution {
public:
int minKBitFlips(vector<int>& nums, int k) {
int nums_size = nums.size(), i;
int cnt = 0;
queue<int> q;
for (i = 0; i < nums_size; ++i) {
if (!q.empty() && k + q.front() - 1 < i) q.pop();
if ( !( (q.size() % 2) ^ nums[i] ) ) { /* 当前位置需要翻转 */
if (i + k > nums_size) return -1; /* 最后k-1个位置还需要翻转,则无法实现 */
q.push(i);
++cnt;
}
}
return cnt;
}
};
东方欲晓,莫道君行早。

浙公网安备 33010602011771号