【leetcode】前缀和+哈希表

和相同的二元子数组


class Solution {
    public int numSubarraysWithSum(int[] nums, int goal) {
        int n=nums.length;
        int []sum=new int[n+1];
        //前缀和
        for (int i = 1; i <=n ; i++) {
            sum[i]=sum[i-1]+nums[i-1];
        }
        Map<Integer,Integer> map=new HashMap<>();
        map.put(0,1);
        int ans=0;
        for (int i = 0; i <n ; i++) {
            int r=sum[i+1];
            int l=r-goal;
            ans+=map.getOrDefault(l,0);
            map.put(r,map.getOrDefault(r,0)+1);
        }
        return ans;


    }
}

map.put(0,1) 是为了只有一个数的情况

心得 :多练 看不懂时候就照着代码手动走一遍

最高频元素的频数

法一 :排序 + 前缀和 + 二分 + 滑动窗口

class Solution {
    int []nums,sum;
    int k,n;
    public int maxFrequency(int[] nums_, int k_) {
        nums=nums_;
        k=k_;
        n=nums.length;
        sum=new int[n+1];
        Arrays.sort(nums);
        for(int i=1;i<n+1;i++){
            sum[i]=sum[i-1]+nums[i-1];
        }
        int l=0;
        int r=n;
        while(l<r){
            int mid=l+((r-l+1)>>1);
            if(check(mid)){
                l=mid;
            }
            else{
                r=mid-1;
            }
        }
        return r;
    }
    public boolean check(int len){
        for(int l=0;l+len-1<n;l++){
            int r=l+len-1;
            int cur=sum[r+1]-sum[l];
            int tmp=nums[r]*len;
            if(tmp-cur<=k) return true;

        }
        return false;
    }
}

先对原数组 numsnums 进行从小到大排序,如果存在真实最优解 lenlen,意味着至少存在一个大小为 lenlen 的区间 [l, r],使得在操作次数不超过 kk 的前提下,区间 [l, r], 的任意值 nums[i] 的值调整为 nums[r]。

法二:枚举

,先对原数组 numsnums 进行排序,然后枚举最终「频数对应值」是哪个。

利用每次操作只能对数进行加一,我们可以从「频数对应值」开始往回检查,从而得出在操作次数不超过 k 的前提下,以某个值作为「频数对应值」最多能够凑成多少个。

class Solution {
    public int maxFrequency(int[] nums, int k) {
        int n=nums.length;
        Map<Integer,Integer> map=new HashMap<>();
        int ans=1;

        //计数
        for(int i=0;i<n;i++){
            map.put(nums[i],map.getOrDefault(nums[i],0)+1);
        }
        List<Integer> list=new ArrayList<>(map.keySet());
        Collections.sort(list);

        for(int i=0;i<list.size();i++){
            int x=list.get(i);
            int cnt=map.get(x);
            if(i>0) {
                int p = k;
                for (int j = i - 1; j >= 0; j--) {
                    int y = list.get(j);
                    int cha = x - y;
                    if (p >= cha) {
                        int min = Math.min(p / cha, map.get(y));
                        p -= min * cha;
                        cnt += min;
                    } else {
                        break;
                    }
                }
            }
            ans=Math.max(ans,cnt);

        }
        return ans;



    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值