六月集训(第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;
    }
};
posted @ 2022-06-06 11:24  番茄元  阅读(35)  评论(0)    收藏  举报