【问题标题】:Iterator for a list of sorted lists using a priority queue [duplicate]使用优先级队列的排序列表列表的迭代器[重复]
【发布时间】:2018-09-04 05:48:09
【问题描述】:

我找到了以下面试问题here.

SortedIterator - 由具有排序 int 值的列表组成 每个列表。调用 next() 时必须给出下一个排序值。

必须实现方法 * 构造函数 * 下一个() * hasNext()

[ [1, 4, 5, 8, 9], [3, 4, 4, 6], [0, 2, 8] ]

next() -> 0, 1, 2, 3, 4, 4, 4...

我用 Java 写了一个快速实现:

package com.app;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class SortedIterator implements Iterator<Integer> {

    private final List<Integer> mFlattenedList;
    private final Iterator<Integer> mIntegerIterator;

    SortedIterator(final List<List<Integer>> lists) {
        mFlattenedList = flattenLists(lists);
        mIntegerIterator = mFlattenedList.iterator();
    }

    private List<Integer> flattenLists(final List<List<Integer>> lists) {
        final List<Integer> result = new ArrayList<>();
        for (List<Integer> list : lists) {
            for (int value : list) {
                result.add(value);
            }
        }
        Collections.sort(result);
        return result;
    }

    @Override
    public boolean hasNext() {
        return mIntegerIterator.hasNext();
    }

    @Override
    public Integer next() {
        return mIntegerIterator.next();
    }
}

时间:O (K * N) 展平输入列表的列表 + O (N*K) 迭代展平的列表 = O (N * K)

空格:O (N * K) 用于存储展平列表。

N - 列表的数量。

K - 每个列表中的元素数。

但是链接中的answer 说:

有一个使用优先级的时间复杂度为 O(logN) 的解决方案 队列。也许面试官会期待这样的事情,我不知道 知道。

O (log N) 怎么可能?如果使用优先级队列,每次调用hasNext(),我们都需要检查队列是否为空(O(1))。然后我们调用next(),它根据table 从队列中提取最小元素(O(log (N*K),对于任何实现)。由于我们需要调用next() N * K 次,所以我们需要O(N * K * log (N*K) 来遍历所有元素。

【问题讨论】:

  • nestedList.stream().flatMap(identity()).sorted().iterator().
  • @BoristheSpider 这基本上就是 OP 正在做的事情,并且每个元素不会得到 O(log N) 复杂度......
  • O(n lg n) 对于n 元素的每个元素肯定是O(lg n),假设整个数据都被消耗掉了。
  • @BoristheSpider 我敢肯定你不希望你的应用程序在构造一个巨大的SortedIterator 时挂起几秒钟。在预计算复杂度和每元素复杂度之间总是需要权衡取舍。
  • 假设此操作在启动时执行,而不是每个操作执行一次,并且此延迟以某种方式可以检测到,那么是的。例如,如果它是每个请求运行一次的微服务,则没有区别。基本上你是对的,@pkpnd,这是一个吞吐量与延迟的问题——但我不喜欢这些“可爱”的算法问题,因为它们在实践中通常不相关。

标签: java algorithm data-structures priority-queue


【解决方案1】:

解决方案的 O(logN) 复杂度是每个元素的复杂度,而不是遍历所有值的复杂度。

解决方案如下所示:

  • 首先定义一个名为ListValue 的新类,它存储一个值以及它来自的列表的索引。这些应该与使用该值的其他 ListValue 对象相当。

  • 构造函数:初始化一个名为pqPriorityQueue&lt;ListValue&gt;,并将N个列表中每个列表的第一个元素放入pq

  • next():弹出pq前面的ListValue。里面的值是要返回的值,但首先,将ListValue 列表中的下一个元素移动到pq。复杂度为 O(log N),因为我们删除一个元素并添加一个元素到 pq,其中最多包含 N 个元素。

请注意,该解决方案不会一次将所有 N*K 值保留在优先级队列中,只保留 N 个列表中每个列表中的单个“下一个”值。因此,优先级队列始终(最多)有 N 个元素,所以它的操作都是 O(log N)。

要理解为什么会这样,请记住每个列表已经排序,因此最小未使用值必须出现在某些列表的“前面”(不包括已使用的值)。然后,请注意优先级队列恰好包含每个列表的“前”元素——当我们从与我们删除的元素相同的列表中添加一个元素到pq 时,我们强制这发生在next() 中。因此,pq 将始终包含最小未使用值(直到所有值都用完)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-28
    • 1970-01-01
    • 2022-11-11
    • 2014-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多