【问题标题】:Not sure what kind of algorithm this problem requires / what data structure (Printer Queue problem)不确定这个问题需要什么样的算法/什么样的数据结构(打印机队列问题)
【发布时间】:2019-07-08 04:28:21
【问题描述】:

这几乎是一个打印机队列问题。

示例输入:

6 0
1 1 9 1 1 1

第一行 = 两个数字,第一个是打印机作业的数量,第二个是您的作业在队列中的位置

第二行 = 每个作业的优先级。列出的第一个数字是第一个作业的优先级,依此类推。数字越大,优先级越高。

打印机无限期地运行这个循环:

  1. 读取队列头部的作业 J。
  2. 如果队列中有另一个作业的优先级高于 J,请将 J 移到队列末尾。
  3. 否则,执行作业 J(需要 1 分钟才能完成)并将其从队列中移除。

输出距离打印机完成作业的分钟数。

问题是位置很重要。因此,正如您在测试用例中看到的那样,您的作业在队列中排在第一位,这意味着它会被移到后面,因为它不是最高优先级,然后第二个作业也会被移到后面,并且您的作业将在 5 分钟后完成打印。

我认为 LinkedList 最适合这种情况,但您必须跟踪最高优先级,该优先级是动态更改的。 PriorityQueue 的问题是元素是基于一些比较器插入的,而我的结构的初始排序将基于位置。此外,您不能添加到 PriorityQueue 的后面。

所以,就知道要使用哪种结构,或者这个问题是否涉及任何结构而言,我有点卡在这里。

【问题讨论】:

  • 评论不用于扩展讨论;这个对话是moved to chat
  • 我已经澄清了我的答案并结合了你的例子。我意识到前面的描述有点快。如果不清楚或没有回答您的问题,请您看一下并告诉我?

标签: java algorithm data-structures


【解决方案1】:

这是错误的-我已经在底部写了原因:

[[遍历列表。在您的索引之前,将具有相同或高于您的优先级的每个元素计算为一个。在您的索引之后,仅将优先级严格高于您的元素的元素计算为一个,直到最后一个具有更高优先级的索引。在该索引之后,继续将与您具有相同优先级的所有元素计数为一个。这为您提供了将在您的元素之前打印的元素数量,因此为您自己的元素添加一分钟。

我希望这会有所帮助。

编辑:

澄清一下:让我们根据优先级重命名队列中的所有元素。 l 较低,e 相等,h 较高。 w 是通缉文件。那么问题的顺序是:

w e h e e e

我们首先计算 w 之前的 eh 的数量,因为这些将在 之前打印w。 (e 被移到 w 之前的队列后面,h 被首先处理。)在这个例子中, 之前没有元素w,所以我们算 0。

w之后,我们只计算h的,因为它们被移到队列的前面。本例中只有 1 个。

最后,我们统计w之后最后一个h之后的e的个数(如果有h 在 w 之后),因为 w 被移到了这些 e 的后面。有 3 个,所以在我们自己之前总共有 4 个打印作业。添加我们自己的打印作业,我们总共得到五个作业/分钟。

为此,我们需要查看列表两次,一次查找最后一个h,一次进行计数。

编辑:

举一个新的例子。假设我们的队列是 2, 2', 9, 8, 2, 1, 7,其中 2' 是我们的文档。

首先发生的事情是前 2 被发送到队列的后面,然后是 2':

2 2' 9 8 2 1 7
2' 9 8 2 1 7 2
9 8 2 1 7 2 2'

然后打印 9 和 8,留下 2、1、7、2、2'。现在 2 和 1 被发送到后面。

2 1 7 2 2'
1 7 2 2' 2
7 2 2' 2 1

然后打印 7。我们剩下 2, 2', 2, 1。这些是按顺序打印的,而 2' 作为整体的第 5 个元素打印。

如果我们按照上面的过程,我们将把它改写为:

2 2 9 8 2 1 7
e w h h e l h

直到 w,我们统计了 0 次 h 和 1 次 e。这是后来在我们自己之前打印的 2。在 w 之后,我们计算 3 个 h 和最后一个 h 之后的 0 个 e。这意味着有三个元素(9、8 和 7)将在我们自己之前打印,而 el(2 和 1)不会。

我们总共计算了 4 个打印在我们自己之前的元素,而我们的是第 5 个。]]

我没有考虑过元素可能需要几轮。当较高优先级的作业按降序排列时,上述情况成立,但如 ruakh 所指出的,反例是 (1', 2, 1, 3)。

【讨论】:

  • 问题是关于计算自己的文档打印之前所花费的时间。答案计算了其他文档的数量,所以应该为自己的工作索引加 1(或者我猜是在第一次运行时计算它)。每份文件的打印时间为 1 分钟。
  • 当然可以,但为什么要“为自己添加一分钟”?
  • 嗯,我的意思是,'为了你自己的 [元素]'。如,“在到目前为止计算的等待时间上增加一分钟,以将您自己文档的打印时间考虑在内”。你能详细说明吗?我是这个论坛的新手,我应该扩展/澄清答案吗?
  • 如果队列如下所示,您能否逐步说明它是如何工作的:2 2(我们的工作) 9 8 2 1 7
  • 这个答案是错误的。考虑1 2 1 3。第二个1 在第一个之前打印,但这个答案认为第一个1 在第二个之前打印。
【解决方案2】:

编辑:我写道@MinosIllyrien 的答案是正确的,但事实并非如此。但是,我想我可以解决我的答案。如果您认为我失败了,请随时发表评论。

这是我自己的解释:

假设你有三类人:

  • 比你更重要(MITY),
  • 和你一样重要 (AIAY),
  • 不如你重要 (LITY)。

在一个公平的世界里,会发生什么?首先是 MITY 传球,然后是排在你前面的 AIAY 传球,轮到你了(不管有多少 LITY:公平点,但不要太多)。

但在你的世界中,每次 MITY 经过时,他/她都会改变 AIAY 的顺序。在最后一个 MITY 过去之前,这无关紧要。如果他/她在你之前,没问题。但是如果他/她在你身后,你和他/她之前的所有 AIAY 都会被移到后面。因此,背后的 AIAY 在您之前,而在您之前的 AIAY 仍然在您之前。因此,在你之后唯一剩下的 AIAY 是你和最后一个 MITY 之间的那些。

编辑:问题是 MITY 的顺序:它们不是按位置排序(MinosIllyrien 回答中的问题),而是 按优先级和按位置排序。上面的部分没有缺陷并且保持不变。

如果您需要输出已排序的作业,您也不需要特定的数据结构。这是一个带有简单链表的算法(或两个数组列表:一个用于存储作业,一个用于标记已执行的作业)

假设作业列表不为空。

  1. 让 Ps = 有序的优先级集,从最大值到最小值
  2. 让 last_pos = 0
  3. 让 P = Ps.pop() 和 start_pos = last_pos
  4. 执行(并删除)优先级为 P 的所有作业,从 P 的 start_pos 到 last_pos(从 end 到 start 倒带)
  5. 如果 Ps 不为空,则返回 3,否则结束。

步骤 1 的时间复杂度为 O(n log n),然后 Ps 中的每个 P 的时间复杂度为 O(n),即 O(n log n + n * Ps.size)。如果您知道优先级的边界,则步骤 1 仅使用桶排序是 O(n),因此整个序列的复杂度为 O(n * Ps.size)。

【讨论】:

    【解决方案3】:

    如果你真的想模拟打印机的行为,我认为正确的方法是使用链表(或数组加上一个整数来跟踪你在重复循环时的当前位置)加 em> 优先级队列。每当您发现链表头部的值与优先级队列中的顶部值匹配时,您就将其从两者中删除。这种方法需要最坏情况 O(n2) 时间。

    但如果你只想找到分钟数,你可以在最坏的情况下做到这一点 O(n log m)时间,其中 n 是作业总数,m 是不同优先级的数量。 (m ≤ n,所以这也是最坏的情况O(n log n em>) 时间。) 这是一种方法:

    1. 构建从每个优先级值到具有该优先级的作业队列索引列表的TreeMap<Integer, ArrayList<Integer>> 映射。
      • 这需要 O(n log m) 时间,其中 m 是不同优先级的数量队列。
      • 作为一项小型优化,我们可以跳过任何低于感兴趣作业的优先级值。
    2. 初始化int lastPos = -1int numJobsCompleted = 0
    3. 迭代映射中的值(= 作业队列索引列表),从最大的优先级值开始,向下移动到我们感兴趣的作业的优先级值。对于每个列表索引,找到小于lastPos 的最大作业队列索引(= 列表元素),如果有的话;否则,取最大的作业队列索引(= 列表元素)。在任何一种情况下,将lastPos 更新为该作业队列索引,并更新numJobsCompleted 以添加作业队列索引列表的大小。
      • 这里的想法是,当我们检查了所有大于或等于某个值的优先级时,lastPos 指向作业队列中最新完成项的索引;这样我们就可以处理下一个优先级的作业,从索引 lastPos+1 开始,到索引 lastPos-1 结束(当然,在 n 处环绕)。
      • 如果我们在数组列表上使用线性搜索,这需要最坏情况 O(n)。
      • 作为一个小优化,我们可以对数组列表使用二分查找。
      • 作为一个小的优化,我们可以从扫描大于或等于我们感兴趣的作业的优先级值并且在其数组中恰好有一个作业队列索引的最小优先级值开始-列表。亲
    4. 当我们达到我们感兴趣的工作的优先级值时,我们只需要找到lastPos和我们感兴趣的工作的索引之间的工作索引数,并更新@987654331 @ 因此。这可以通过线性搜索 - 最坏情况 O(n) - 或二分搜索 - 最坏情况 O(log n)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-10
      • 1970-01-01
      相关资源
      最近更新 更多