1846. 减小和重新排列数组后的最大元素
前言:
这是一道不应该是中等题的简单题,因为确实常规方法也能做出来
我就用了两种方法,一种就是排序+贪心,另外一种就是计数(哈希?)+贪心
贴个题目:
代码示例
解题思路
第一种:排序+贪心算法
首先我们先排序,然后根据题目说第一个元素必须为1,因此有
arr[0]=1
紧接着因为求的是最大值,根据贪心算法,我们让每一元素都满足以下条件即可:
abs(arr[i] - arr[i - 1]) <= 1
最后返回最后一个元素就可以了
第一种代码:
int compare(const void *a,const void *b)
//升序排列
{
return *(int *)a-*(int *)b;
}
int maximumElementAfterDecrementingAndRearranging(int* arr, int arrSize){
qsort(arr,arrSize,sizeof(int),compare);//升序排列
arr[0]=1;//让第一个元素为1
for(int i=1;i<arrSize;i++)
{
if(abs(arr[i]-arr[i-1])>1)
//如果不满足abs(arr[i] - arr[i - 1]) <= 1
{
arr[i]=arr[i-1]+1;//就强行满足条件
}
}
return arr[arrSize-1];//因为是升序,所以返回最后一个元素即可
}
性能分析:
时间分析:
使用了快速排序,平均值为:O(nlogn),然后一次循环:O(n),两者相加得最后的时间复杂度是:O(nlogn)+O(n)=O(nlogn)
空间复杂度:
快速排序空间复杂度为:O(logn),其他开销是常数,因此空间复杂度是:O(logn)
第二种:计数(哈希?)+贪心
这里我们读题目可以发现一个隐含条件,就是数组元素的最大值小于等于数组长度arrSize,利用这一个性质我们可以使用计数排序
新建一个数组,haxarr,长度要比arr多一,因为arr里面没有0,因此haxarr[0]是0,不用管,遍历也是从下标1开始
然后将arr中元素映射到haxarr中,注意使用上述隐含条件,如果遇到元素大于数组长度,就存进haxarr[arrSize]中,因此有:
haxarr[(int)fmin(arr[i],arrSize]++
(int)强制类型转换,因为fmin返回值是浮点数
然后我们就从下标1开始遍历haxarr数组,根据题意,arr数组应该是一个连续的数组,那么对应haxarr数组来说,就是从下标1开始,不能出现元素为0的情况
一旦出现了,就要用其他元素来填补这一个空,那么就有:
miss-=fmin(haxarr[I]-1,miss)
//haxarr[I]-1是因为,怎么填补也要给自己留一个
//fmin是因为miss不能是负数
然后最后填补完成之后,你会发现有miss个无法填补,因此最大的元素应该是arrSize-miss
return arrSize-miss
第二种代码:
int maximumElementAfterDecrementingAndRearranging(int *arr, int arrSize) {
int haxarr[arrSize+1];//创建一个大小+1 的哈希数组,因为原数组没有0元素
memset(haxarr,0,sizeof(haxarr));//数组初始化为0
for(int i=0;i<arrSize;i++)
{
haxarr[(int)fmin(arr[i],arrSize)]++;
//将arr中的元素映射到haxarr中,其中根据题意最大为arrsize,强制类型转换int
}
int miss=0;
for(int i=1;i<arrSize+1;i++)
{
if(haxarr[i]==0) miss++;
else miss-=fmin(haxarr[i]-1,miss);//miss不可能是负数,因此最大减掉miss
}
return arrSize-miss;
}
性能分析:
时间分析:
因为这里没有排序,只是用了一次循环,因此时间复杂度是:O(n)
空间分析:
这里新建了一个arrSize+1的数组,因此空间复杂度是:O(n)
第二种做法是双百做法!