[M贪心] lc1838. 最高频元素的频数(前缀和+二分+双指针+滑动窗口+周赛238_2)

1. 题目来源

链接:1838. 最高频元素的频数

2. 题目解析

贪心+二分答案。

双指针也可以做,单调性可证明,ai 确定的左边连续的 j,当 ai 变大时,j 单调向后走,不会向左再走了,可以使用双指针。

其实就是个滑动窗口。


最高频数一定可以为原数组数,因为这 k 次操作不是必须全部用完的。

枚举答案 ai,仅需判断操作 k 次的下,最多能将多少数变成 ai。且一定是操作 ai 前面连续的一段,因为只能 +1,所以后面的大于 ai 的数不在考虑范围内,且从左向 ai 变的话一定不如从 ai 向左变好。

假设在 j 坐标停下,[j, i] 区间中的数都能变成 ai,那么实际上操作的次数之和就是 ( a [ i ] − a [ j ] ) + ( a [ i ] − a [ j + 1 ] ) + . . . + ( a [ i ] − a [ i − 1 ] ) + ( a [ i ] − a [ i ] ) (a[i]-a[j])+(a[i]-a[j+1])+...+(a[i]-a[i-1])+(a[i]-a[i]) (a[i]a[j])+(a[i]a[j+1])+...+(a[i]a[i1])+(a[i]a[i]),其实就是 (i-j+1)*a[i]+s[j:i]。其中 s[j:i] 就是 a[j]+a[j+1]+..+a[i] 区间和,利用前缀和数组进行优化。


时间复杂度: 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),比较容易分析。

class Solution {
public:
    int maxFrequency(vector<int>& nums, int k) {
        typedef long long LL;

        sort(nums.begin(), nums.end());
        int n = nums.size();
        vector<LL> sum(n + 1);
        for (int i = 1; i <= n; i ++ ) sum[i] = sum[i - 1] + nums[i - 1];

        int res = 0;
        for (int i = 1; i <= n; i ++ ) {
            int l = 1, r = i;
            while (l < r) {
                int mid = l + r >> 1;
                if (nums[i - 1] * (i - mid + 1ll) - (sum[i] - sum[mid - 1]) > k) l = mid + 1;
                else r = mid;
            }
            res = max(res, i - r + 1);
        }

        return res;
    }
};

双指针, O ( n ) O(n) O(n),需要特别分析 i 向后移动的过程中,j 指针不会向后移动。很明显的滑动窗口了。

class Solution {
public:
    int maxFrequency(vector<int>& nums, int k) {
        typedef long long LL;
        sort(nums.begin(), nums.end());

        int n = nums.size();
        vector<LL> s(n + 1);
        for (int i = 1; i <= n; i ++ ) s[i] = s[i - 1] + nums[i - 1];

        int res = 0;
        for (int i = 1, j = 1; i <= n; i ++ ) {
            while ((i - j + 1ll) * nums[i - 1] - (s[i] - s[j - 1]) > k) j ++ ;
            res = max(res, i - j + 1);
        }

        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值