Leetcode 1838最高频元素的频数

Leetcode 1838最高频元素的频数

题目链接

问题描述

  • 题目原文:

元素的 频数 是该元素在一个数组中出现的次数。
给你一个整数数组 nums 和一个整数k 。在一步操作中,你可以选择 nums 的一个下标,并将该下标对应元素的值增加 1
执行最多 k 次操作后,返回数组中最高频元素的 最大可能频数
来源:力扣(LeetCode)

  • 参数要求:

1 <= nums.length <= 1 0 5 10^5 105
1 <= nums[i] <= 1 0 5 10^5 105
1 <= k <= 1 0 5 10^5 105

思路

  1. 一个无序的数组,没有什么太好的思路,因此尝试改变数组的形式。
  2. 因为数组的没有规定顺序(递增或者递减),所以首先判断如果改变数组元素的顺序是否影响结果。如果不影响,将数组转换成有序递增的。
  3. 我们在这时候很容易发现如果采用答案在数组中变成连续的,因此尝试采用滑动窗口。
  4. 设置滑动窗口为[l,r],将r作为区间的基准,即所有元素通过增加1的操作变成r,统计需要的次数count。
  5. 如果count<=k说明当前的区间是合适的,可以将他和我们记录的结果进行比较,选择一个较大的数,然后r继续向右移动
  6. 如果count>k说明当前的区间太大,必须要""掉左边的一部分元素(l向右移),重新开始计算count。
  7. 上面移动边界的时候重新计算count的时候,说的有一些语焉不详,不太会画图,文字表述有一些抽象,如果有朋友参考的话,可以自己画图试试看。

代码

  • 滑动窗口
public int maxFrequency(int[] nums, int k) {
        Arrays.sort(nums);
        int res = 1;
        int l = 0;
        int r = 0;
        int count = 0;
        int len = nums.length;
        while (l<=r&&r<=len-1){
            if (count<=k){//移动右边界
                r++;
                if (r>len-1){
                    break;
                }
                count += (r-l)*(nums[r]-nums[r-1]);
            }
            else{//移动左边界
                l++;
                if (l>r){
                    break;
                }
                count -= nums[r]-nums[l-1];
            }
            if (count<=k){//有效的话,进行判断取最大值
                res = Math.max(res,r-l+1);
                System.out.println(nums[r]);
            }
        }
        return res;
    }
  • 滑动窗口+前缀数组(这里贴一份前缀数组的代码,思路大同小异,只是在count的计算上有差异)
int[] nums;
    int[] arr;
    public int maxFrequency(int[] nums, int k) {
        Arrays.sort(nums);
        int len = nums.length;
        this.arr = new int[len];
        this.nums = nums;
        arr[0] = 0;
        for (int i = 1; i < len; i++) {
            arr[i] = arr[i-1] + i*(nums[i]-nums[i-1]);
        }
        int r = 0;
        int l = -1;
        int res = 1;
        while (l<r&&r<=len-1){
            int call_ret = getInterVals(l,r);
            if (call_ret<=k){
                r++;
                if (r>=len){
                    break;
                }
            }
            else{
                l++;
            }
            int count = getInterVals(l,r);
            if (count<=k&&res<r-l){
                res = r-l;
            }
        }
        return res;
    }
    //获取区间(l,r]
    private int getInterVals(int l,int r){
        if (l==-1){
            return arr[r];
        }
        else {
            return arr[r]-arr[l] - (nums[r]-nums[l])*(l+1);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值