题目链接:3134. 找出唯一性数组的中位数(困难)
算法原理:
解法:二分查找+滑动窗口
击败7.55%
时间复杂度O(Nlogn)
二分查找模板👇
优选算法-二分:18.在排序数组中查找元素的第一个和最后一个位置
①确定中位数位置:
nums 的唯一性数组的数量就是 nums 的非空连续子数组的个数
一共有m=1+2+⋯+n=2n(n+1) 个非空连续子数组
当 m=4 时,中位数是第 2 小元素,m=5 时,中位数是第 3 小元素
所以中位数是这 m 个数中的第k=(m+1)/2小
②二分查找调节mid找k(求最左端点模板)
以 "子数组的不同元素个数" 为二分对象(左边界 0、右边界 n),每次取中间值
mid,判断 "不同元素数≤mid 的子数组数量" 是否≥k:while(left<right)
1.分二段,发现左无= 右有 --->左无=就求左端点->check确定等号在右边,所以是求左端点
2.注意mid靠左:mid=left+(right-left)/2->确定mid咋写
3.if(mid在最左端点的左边)让左端点的左边往里靠,还要超过:left=mid+1->mid在最左端点的左边就是!check
4.else 另一边靠过来就行:right=mid
5.返回left或者right都行(因为最终会重合)
③用封装的check方法来判断是否覆盖第k小(ret>=k返回true)
维护窗口
[left, right],保证窗口内不同元素数≤mid,累加合法子数组数(right-left+1),数量≥k 则提前返回 true答疑
Q1:m既然是总的非空连续子数组的个数,那里面还有可能存在重复的元素呢
唯一性数组是:[1,1,1,1,2,2](长度 m=6,和子数组总数一致)------这里的元素可以重复,但数组长度固定为 m,中位数的位置只由长度 m 决定,和元素值是否重复无关
Java代码:
java
class Solution {
public int medianOfUniquenessArray(int[] nums) {
int n=nums.length;
long k=((long)n*(n+1)/2+1)/2;//中位数的位置,第k小的数
//求左端点模板↓
int left=0,right=n;
while(left<right){
int mid=left+(right-left)/2;//取靠左的位置
//mid是不断调节的,目标位置在k
//检查不同元素个数<=mid时的子数组数量是否>=k
if(!check(nums,mid,k)) left=mid+1;//比k小,left往右调整
else right=mid;//比k大,right往左调整
}
return right;
}
//检查是否覆盖第k小,ret>=k算覆盖到k
private boolean check(int[] nums,int upper,long k){
long ret=0;
int n=nums.length,kinds=0;
//<元素,个数>
Map<Integer,Integer> hash=new HashMap<>();
for(int left=0,right=0;right<n;right++){
//进窗口
int in=nums[right];
if(hash.getOrDefault(in,0)==0) kinds++;
hash.put(in,hash.getOrDefault(in,0)+1);
//出窗口
while(kinds>upper){
int out=nums[left];
hash.put(out,hash.get(out)-1);
if(hash.get(out)==0){
hash.remove(out);
kinds--;
}
left++;
}
//更新
ret+=right-left+1;
//判断是否提前返回(无需遍历完所有子数组)
if(ret>=k) return true;
}
return false;
}
}