问题:
在10亿个数字里面,找出最大的前N个数字。
代码:
/**
* 获取TopN
* @param {*} arr 原始数组
* @param {*} topN 需要获取最大值的数量,正整数
*/
function getTopN(arr, topN) {
//链表结构,用来存储topN的信息
//链表结构更容易删除插入
//链表内部元素的结构 {val:0,prev:null,next:null}
var linkedList = {
length: 0,//当length为1时候,只有first元素,没有last元素
first: null,//头元素的prev为null
last: null//尾元素的next为null
};
var len = arr.length;
//循环需要进行Top获取的数组
//首先对前topN的数组元素进行排序,以后的数组元素值进行比较,进行元素的插入与删除操作即可
for (var i = 0; i < len; i++) {
//链表是否已经满了
var isDone = linkedList.length >= topN ? true : false;
//如果链表满了
//说明链表中的元素已经满了则需要对linkedList内部的元素进行比较,需要进行删除插入等操作了
if (isDone) {
//如果链表的最后一个元素的值都大于等于arr[i]
//则说明arr[i]比链表中的任意一个都小于等于,则可以抛弃,进入下一次循环
if (linkedList.last.val >= arr[i]) continue;
}
//如果arr[i]不小于最后的元素,则需要对链表进行循环,插入适合的位置上
//如果length == 0说明没有元素,表示链表结构才刚开始,需要进行赋值操作
if (linkedList.length == 0) {
linkedList.first = {
val: arr[i],
prev: null,
next: null
}
linkedList.length++;
continue;
}
var item = linkedList.first;
//有初始元素,则进行可以循环
while (item) {
//如果内部元素的值大于arr[i],则进入下一个循环
if (item.val > arr[i]) {
//如果链表已经满了,则进入下一个循环,因为在链表满了情况下,下一个必然会有值
if (isDone) {
item = item.next;
continue;
}
//如果没有满,且链表的长度为1,表示现在只有头元素,没有尾元素
if (linkedList.length == 1) {
linkedList.last = {
val: arr[i],
prev: item,
next: null
}
linkedList.first.next = linkedList.last;
linkedList.length++;
break;
}
//即没有满又不是length为1则继续循环
item = item.next;
continue;
}
//如果内部元素的值小于arr[i],则插入
//将该内部元素的上级给arr[i]新建的元素,arr[i]新建的元素的下级为该内部元素
var newTemp = {
val: arr[i],
prev: item.prev,
next: item
}
//内部元素原本的上级的下级变成arr[i]的新建元素
//当内部元素原本的上级不存在的时候,即该内部元素为头元素,则不需要进行如此操作
if (item.prev) item.prev.next = newTemp;
//将该内部元素的上级变成arr[i]新建的元素
item.prev = newTemp;
//如果arr[i]的新建元素的上级为null,则该新建元素为新的头元素,则将链表的first属性重新赋值
if (!newTemp.prev) linkedList.first = newTemp;
//如果链表满了,则需要进行最后元素的删除与重新赋值操作
if (isDone) {
//删除最后的元素,将最后元素的前一个元素赋值给新的最后元素
//同时将新的最后元素的next赋值为null
linkedList.last = linkedList.last.prev;
linkedList.last.next = null;
} else {
if (linkedList.length == 1) {
linkedList.last = newTemp.next;
}
linkedList.length++;
}
break;
}
}
var temp = [];
var item = linkedList.first;
while (item) {
temp.push(item.val);
item = item.next;
}
return temp;
}
逻辑:
先将前N个数字进行大小排序,然后后面的数组元素与前N个排好序的进行比较。
JS中没有链表这个数据结构,因此代码繁杂了一点,若是JAVA可以直接用LinkedList来做。
时间复杂度:
O(n)
一开始的排序用来插入排序的思想,N位之后则是链表的比较,删除与插入。