当前位置: 首页 > article >正文

滑动窗口算法-day11(不定长选做)

1.每种字符至少取 K 个

题目

解析

  • 要求取两边的元素,且三种元素数量不能小于 K;
  • 反向思维转化为:先计算每个元素个数到 cnt,构建窗口,依次消减 cnt,若新进队元素 x 使得 cnt[x] < K,则移动窗口;
  • 注意点:若本身就有元素总数小于 K,直接返回 -1;

代码

class Solution {
public:
    int takeCharacters(string s, int k) {
        // 时间复杂度:O(n)
        // 空间复杂度:O(1)

        int n = s.size();
        int ans = 0;

        unordered_map<char,int> cnt;
        for(char c : s) cnt[c] ++;

        // 如果任何字符的数量小于 k,直接返回 -1
        if (cnt['a'] < k || cnt['b'] < k || cnt['c'] < k) {
            return -1;
        }

        int l = 0;
        for(int r = 0;r < n;r ++) {
            cnt[s[r]] --;

            while(cnt[s[r]] < k){
                cnt[s[l]] ++;
                l ++;
            } 

            ans = max(ans,r - l + 1);
        }

        return n - ans;
    }
};

2.数组的最大美丽值

题目

解析

  • 由于答案记录最终数组中最多相等的数,所以与数组顺序无关,直接排序;
  • 将每个数字 x 想象成一个数值范围,例如 (x - k, x + k),(y - k, y + k);
  • 若要两个数字可以转换,则需要满足 x + k >= y - k,即 y - x <= 2 * k;
  • 遍历数组,若两头数字不满足条件转换,则令 L++;满足则更新答案;

代码

class Solution {
public:
    int maximumBeauty(vector<int>& nums, int k) {
        // 时间复杂度:O(nlogn)
        // 空间复杂度:O(1)

        int n = nums.size();
        int ans = 0;

        sort(nums.begin(),nums.end());// 排序不影响结果

        int l = 0;
        for(int r = 0;r < n;r ++){
            // 若右边界元素和左边界元素取值范围无交集,则移动窗口
            while(nums[r] - nums[l] > 2 * k){
                l ++;
            }

            ans = max(ans,r - l + 1);
        }

        return ans;
    }
};

3.最高频元素的频数

题目

解析

  • 题目要求最高频元素的频数,与数组顺序无关,直接排序;
  • 核心思想:计算窗口每个元素与右边界元素的距离和
  • 一开始我的思路是加上每两个元素之间的差值,使其小于 k,但其实不是这样算;
  • 计算公式为:(nums[r] - nums[r - 1]) * (r - l)
  • 当距离和超过 K 时,就要移动窗口,没超过就更新答案最大值;

公式推导:

画出来的面积就是窗口每个元素与右边界元素的距离和nums[r] - nums[r - 1] 是矩形高,r - l 是矩形宽;

代码

class Solution {
public:
    int maxFrequency(vector<int>& nums, int k) {
        // 时间复杂度:O(nlogn)
        // 空间复杂度:O(1)

        int n = nums.size();
        int ans = 1;
        long long sum = 0;

        sort(nums.begin(),nums.end());

        int l = 0;
        for(int r = 1;r < n;r ++){
            // 计算窗口内元素到窗口右边界元素距离总和
            sum += (long long)(nums[r] - nums[r - 1]) * (r - l);

            while(sum > k) {
                // 减去窗口左边界元素到右边界元素距离
                sum -= nums[r] - nums[l];
                l ++;
            }

            ans = max(ans,r - l + 1);
        }

        return ans;
    }
};

http://www.kler.cn/a/585014.html

相关文章:

  • LLM的准确率评估采用什么方式:准确率评估使用的是 `sklearn.metrics` 模块中的 `accuracy_score` 函数
  • AI学习——深度学习核心技术深度解析
  • 父组件中循环生成多个子组件时,有且只有最后一个子组件的watch对象生效问题及解决办法
  • Vue前端页面实现搜索框的重置
  • vue3 + xlsx 实现导入导出表格,导出动态获取表头和数据
  • [微服务设计]3_如何构建服务
  • golang从入门到做牛马:第二十二篇-Go语言并发:多任务的“协同作战”
  • 详细解析 ListView_GetEditControl()
  • Linux入门 全面整理终端 Bash、Vim 基础命令速记
  • Xxl-Job学习笔记
  • Vue系统学习day01
  • 258.反转字符串中的单词
  • 【每日学点HarmonyOS Next知识】span问题、组件标识属性、属性动画回调、图文混排、相对布局问题
  • Linux 部署Java应用程序
  • OpenCV实现图像分割与无缝合并
  • FORTRAN语言的数据结构
  • GStreamer —— 2.17、Windows下Qt加载GStreamer库后运行 - “播放教程 5:色彩平衡“(附:完整源码)
  • FastJSON与Java序列化:数据处理与转换的关键技术
  • Python爬虫实战:基于 Scrapy 框架的腾讯视频数据采集研究
  • 『Rust』Rust运行环境搭建