我正在尝试创建在特定时间运行的代码。我的第一种方法应该在O(log k)中以最差的方式运行。这是我的方法:
public void count(T x) {
if(heap.size() < k){
heap.add(x);
}
else if(heap.size() == k && x.compareTo((T) heap.peek()) > 0){
heap.remove();
heap.add(x);
}
}
我无法计算运行时间。我敢肯定,heap.size()调用是恒定时间。尽管add()方法在O(log k)时间中运行。 remove()方法也是如此。其他比较也应该只花费固定的时间。因此,我很确定我的程序在O(log k)中运行。有人可以确认吗?
我的另一种方法应该在O(k log k)时间中运行。这是我的方法:
public List<T> kbest() {
//empty queue first and then restore
List<T> list = new ArrayList<T>();
int size = heap.size();
for(int i = 0; i < size; i++){
list.add(0, heap.poll());
}
for(int j = 0; j < list.size(); j++){
heap.add(list.get(j));
}
return list;
}
这个让我更困惑。列表中的add()以恒定的时间运行。而堆中的add()在O(log k)中运行。获取堆的大小是恒定的,列表的大小也是恒定的(完成“ j”次)。这会使我的运行时O(n)变成线性吗?
答案 0 :(得分:2)
我们一行一行地做。
public void count(T x) {
if(heap.size() < k){ // O(1)
heap.add(x); // O(log k)
}
else if(heap.size() == k && // O(1)
x.compareTo(
(T) heap.peek()) > 0) { // O(1)
heap.remove(); // O(log k)
heap.add(x); // O(log k)
}
}
if
块:O(1 * log k)
,即O(log k)
。else if
块:O(max(1, 1) * max(log k, log k))
,即O(log k)
。O(log k)
。现在第二种方法:
public List<T> kbest() {
//empty queue first and then restore
List<T> list = new ArrayList<T>();
int size = heap.size(); // O(1)
for(int i = 0; i < size; i++) { // O(n)
list.add(0, heap.poll()); // O(n)
}
for(int j = 0; j < list.size(); j++){ // O(n)
heap.add(list.get(j)); // O(log n)
}
return list;
}
heap.size
是O(1)
。for
循环是O(n * n)
,即O(n^2)
。for
循环是O(n * log n)
,即O(n log n)
。O(max(1, n^2, n log n))
,即O(n^2)
。要提高kbest()
的时间复杂度,可以使用add()
的{{1}}方法。
当然,顺序会相反。您可以轻松使用O(1)
,即Collections.reverse(list)
。由于这将在循环外部执行,因此时间复杂度不会成倍增加。