LeetCode 1838 Frequency of the Most Frequent Element (二分)

The frequency of an element is the number of times it occurs in an array.

You are given an integer array nums and an integer k. In one operation, you can choose an index of nums and increment the element at that index by 1.

Return the maximum possible frequency of an element after performing at most k operations.

 

Example 1:

Input: nums = [1,2,4], k = 5
Output: 3
Explanation: Increment the first element three times and the second element two times to make nums = [4,4,4].
4 has a frequency of 3.

Example 2:

Input: nums = [1,4,8,13], k = 5
Output: 2
Explanation: There are multiple optimal solutions:
- Increment the first element three times to make nums = [4,4,8,13]. 4 has a frequency of 2.
- Increment the second element four times to make nums = [1,8,8,13]. 8 has a frequency of 2.
- Increment the third element five times to make nums = [1,4,13,13]. 13 has a frequency of 2.

Example 3:

Input: nums = [3,9,6], k = 2
Output: 1

 

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 105
  • 1 <= k <= 105

题目链接:https://leetcode.com/problems/frequency-of-the-most-frequent-element/submissions/

题目大意:给一个数组,每个数字可以加值,总累加值不得超过k,求加完后频数最大的数字的频数

题目分析:提交完看到击败率,就知道不是正解了,看了下related topic是贪心,回头再想。。

当前做法:排序求前缀和,遍历nums,分别计算为了让nums[i]频数尽可能大时其最大的频数,因为前缀和有序,故可二分,二分点(mid)到当前枚举点(curP)这段区间均加到当前枚举点值所需的数值总量可以O(1)算出,通过前缀和可以求出这段区间的和,又知道枚举点值(curV)及区间长度(curP - mid + 1),见cal()方法。这里有个关键优化,就是当两个连续数字相同时,只需算一次即可(显然)

34ms,时间击败42.27%

class Solution {
    
    public long cal(long[] presum, int mid, int curP, long curV) {
        long sum = (mid == 0) ? presum[curP] : presum[curP] - presum[mid - 1];
        //System.out.println("curV = " + curV + " curP = " + curP + " mid = " + mid + " sum = " + sum + " need = " + ((curP - mid + 1) * curV - sum));
        return (long)(curP - mid + 1) * curV - sum;
    }

    public int bsearch(long[] presum, int n, int k, int curP, int curV) {
        int l = 0, r = curP, mid = 0, pos = curP;
        while (l <= r) {
            mid = (l + r) >> 1;
            if (cal(presum, mid, curP, curV) > k) {
                l = mid + 1;
            } else {
                pos = mid;
                r = mid - 1;
            }
        }
        //System.out.println("curP = " + curP + " pos = " + pos);
        return curP - pos + 1;
    }

    public int maxFrequency(int[] nums, int k) {
        Arrays.sort(nums);
        int n = nums.length;
        long[] presum = new long[n];
        presum[0] = nums[0];
        for (int i = 1; i < n; i++) {
            presum[i] = presum[i - 1] + nums[i];
            //System.out.println("sum[" + i + "] = " + presum[i]);
        }
        //System.out.println("biggest = " + presum[n - 1]);
        int ans = 0;
        for (int i = n - 1; i >= 0; i--) {
            if (i < n - 1 && nums[i] == nums[i + 1]) {
                continue;
            }
            ans = Math.max(ans, bsearch(presum, n, k, i, nums[i]));
        }
        return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值