标签:arr int 复杂度 元素 无序 priorityQueue 数组 ArrayList
题目描述
以尽可能小的代价返回某无序系列中的两个最大值,当有重复的时设置某种机制进行选择。
题解
首先要考虑的是重复的数的问题。
A.不处理重复数据方法:在处理第k大的元素时不处理重复的数据,也就是将原数组进行降序排序后,下标为k-1的元素。
B.去除重复数据方法:忽略重复的数据,这时候需要首先对a进行去重处理(可以用哈希表),然后再按A的方法求解。
先排序,再求解:
用快排或堆排序,平均时间复杂度为O(N*logN),然后取出前k个,于是总时间复杂度为O(NlogN)+O(k)=O(NlogN)。
这种做法较浪费时间,因为题目只要求找出第k大的元素,而不需要数组是有序的。
k趟冒泡:
用k趟冒泡排序选出前k大的数。
public static ArrayList<Integer> bubble(int[] arr,int k){
ArrayList<Integer> ans = new ArrayList<>(k);//用数组返回前k大元素,最大的在最前面
for(int i=1;i<=k;i++){
for(int j=0;j<arr.length-i;j++){
if(arr[j]>arr[j+1]){
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
ans.add(arr[arr.length-i]);
}
return ans;
}
时间复杂度为O(N*k)。
部分快排:
在数组中随机选择枢轴mid。
如果右半边(包括a[mid])的长度恰好为k,说明a[mid]就是需要的第k大元素,直接返回a[mid]。
如果右半边(包括a[mid])的长度大于k,说明要寻找的第k大元素就在右半边,往右半边寻找。
如果右半边(包括a[mid])的长度小于k,说明要寻找的第k大元素就在左半边,往左半边寻找。
时间复杂度为O(Nlogk)。如果每次选择的枢轴都是最坏的那个,时间复杂度就会退化为O(Nk)。
借助堆:
借助一个小根堆,先建立一个规模为k的最小化堆,然后每次拿待处理的数组中元素和堆的最小元素(根结点元素值)比较。如果待插入元素大于根结点元素,则在堆中删除根结点,并把待处理的元素入堆。否则可以抛弃这个元素。
public static ArrayList<Integer> heap(int[] arr,int k){
ArrayList<Integer> ans = new ArrayList<>(k);//用数组返回前k大元素,最小的在最前面
Queue<Integer> priorityQueue = new PriorityQueue<>(k);
for (int i : arr) {
if (priorityQueue.size() < k) {//堆还未满,直接入堆
priorityQueue.offer(i);
}else{
if (i >= priorityQueue.element()) {//当前元素大于堆的最小元素,当前元素入堆
//删除堆的最小元后再入堆
priorityQueue.poll();
priorityQueue.offer(i);
}
}
}
while(!priorityQueue.isEmpty()){
ans.add(priorityQueue.poll());
}
return ans;
}
时间复杂度为O(N*logk),因为二叉堆的插入和删除操作都是logk的时间复杂度。
标签:arr,int,复杂度,元素,无序,priorityQueue,数组,ArrayList 来源: https://www.cnblogs.com/hickey2048/p/14604782.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。