1846. 减小和重新排列数组后的最大元素
忙着期末,现在又在实习,太久没刷 leetcode了,今后还会坚持刷下去的。
思路:
这道题不太懂考什么,大概就是先排序,判断第一个是否为1,不为1就减小为1,然后循环到最后一个元素,判断是否相邻元素差值的绝对值是否小于等于1.
代码:
class Solution {
public:
int maximumElementAfterDecrementingAndRearranging(vector<int>& arr) {
sort(arr.begin(),arr.end());
if(*arr.begin() != 1){
*arr.begin() = 1;
}
int len = arr.size();
for(int i=1;i<len;i++){
if(abs(arr[i]-arr[i-1])>1){
arr[i] = arr[i-1] + 1;
}
}
return arr[len-1];
}
};
还有一种很巧妙的贪心
直接在for循环里更改
for(int i=1;i<=len;++i){
arr[i] = min(arr[i],arr[i-1]+1)
}
上述的方法的时间复杂度和排序的速度有关,大概是O(nlogn)
下面的方法能在O(n)解决
我们可以发现,按照题目的要求,可能的最大的数小于等于n,n是arr的长度。
所以有两种情况,第一种是最大的数等于n,也就是从1-n,每个数都有。第二种,一个数重复出现,此时就小于n。
所以我们用一个数组cnt来计数,记录arr里出现的数的数量,当数大于n时,就取为n即可。
那么我们再遍历这个cnt,如果发现没出现的数,就让计数的变量equalnums加一,因为不出现的原因可能大于也可能等于。当出现发现cnt的某一项大于1,说明有重复,那么我们就能让equalnums - min(cnt[i]-1,equalnums),前者-1是因为要留下一个数在该位置,剩下的可以减小来填补空缺的数,如果空缺的数小于能填补的数,那只需要把空缺的数填满即可,所以要取两者最小值
最后剩下的equalnums 用 n减即可。最后的结果就是,如果equalnums=0,那么就相当于没有空缺的数,最大的就为n,如果不等于0,那么就存在相等的数,用n-equalnums就可获得最大的数
代码:
class Solution {
public:
int maximumElementAfterDecrementingAndRearranging(vector<int>& arr) {
int n = arr.size();
vector<int> cnt(n+1);
for(int a : arr){
cnt[min(a,n)]++;
}
int equalnums = 0;
for(int i=1;i<=n;i++){
if(cnt[i]==0){
equalnums++;
}
else
equalnums -= min(cnt[i]-1,equalnums);
}
return n - equalnums;
}
};