和相同的二元子数组
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;
}
}