题意:
给你一个由 n 个正整数组成的数组 nums 。
你可以对数组的任意元素执行任意次数的两类操作:
1.如果元素是 偶数 ,除以 2
例如,如果数组是 [1,2,3,4] ,那么你可以对最后一个元素执行此操作,使其变成 [1,2,3,2]
如果元素是 奇数 ,乘上 2
2.例如,如果数组是 [1,2,3,4] ,那么你可以对第一个元素执行此操作,使其变成 [2,2,3,4]
数组的 偏移量 是数组中任意两个元素之间的 最大差值 。
返回数组在执行某些操作之后可以拥有的 最小偏移量 。
数据范围:
n == nums.length
2 <= n <= 105
1 <= nums[i] <= 109
解法:
因为每种操作都是可以进行无数次的,因此可以将偶数不断除以2,得到最小的奇数,
这样每个数都可以表示为{mi,ma}的数对,mi表示可达到的最小值,ma表示可达到的最大值,
ma通过mi乘2若干次才能得到.
因为这题是要让极差最小,考虑枚举最小值,然后计算出一个最小的最大值,用差值更新答案.
因为只有n个数,一个数不断/2最多log次,那么可能的最小值最多只有O(nlogn)种,存下来之后从小到大排序,
然后将所有{mi,ma}数对丢进set模拟的堆中,
枚举最小值MI时,如果堆顶的数的mi小于当前枚举的最小值MI,那么令mi*=2(前提是乘2之后不超过ma),
当堆中所有数都>=MI时,用最大值-最小值更新答案即可.
code:
#define PI pair<int,int>
class Solution {
public:
int minimumDeviation(vector<int>& a) {
set<PI>s;
vector<int>temp;
int n=a.size();
for(int i=0;i<n;i++){
if(a[i]%2){
temp.push_back(a[i]);
temp.push_back(a[i]*2);
s.insert({a[i],a[i]*2});
}else{
int x=a[i];
temp.push_back(x);
while(x%2==0){
x/=2;
temp.push_back(x);
}
s.insert({x,a[i]});
}
}
sort(temp.begin(),temp.end());
int ans=2e9;
for(auto mi:temp){
while(s.begin()->first<mi&&s.begin()->first*2<=s.begin()->second){
int x=s.begin()->first*2;
int y=s.begin()->second;
s.erase(s.begin());
s.insert({x,y});
}
if(s.begin()->first<mi)break;
ans=min(ans,s.rbegin()->first-s.begin()->first);
}
return ans;
}
};