簡體   English   中英

不確定此問題需要哪種算法/什么數據結構(打印機隊列問題)

[英]Not sure what kind of algorithm this problem requires / what data structure (Printer Queue problem)

這幾乎是一個打印機隊列問題。

輸入樣例:

6 0
1 1 9 1 1 1

第一行=兩個數字,第一個是打印機作業的數量,第二個是作業在隊列中的位置

第二行=每個作業的優先級。 列出的第一個數字是第一個工作的優先級,依此類推。 數字越大,優先級越高。

打印機無限期地運行此循環:

  1. 讀取隊列開頭的作業J。
  2. 如果隊列中還有另一個作業的優先級高於J,則將J移到隊列的末尾。
  3. 否則,執行作業J(需要1分鍾才能完成)並將其從隊列中刪除。

輸出直到打印機完成作業為止的分鍾數。

問題在於位置很重要。 因此,正如您在測試用例中所看到的,您的工作在隊列中的第一個,這意味着它不是優先級最高的,因此它被移到了后面,第二個工作也被移到了后面,並且您的工作將在5分鍾后完成打印。

我認為LinkedList最適合此操作,但是您必須跟蹤最高優先級,該優先級是動態更改的。 PriorityQueue的問題在於,元素是根據某些Comparator插入的,而我的結構的初始順序將基於位置。 另外,您不能添加到PriorityQueue的后面。

因此,我有點想知道要使用哪種結構,或者這個問題是否涉及任何結構。

編輯:我寫道@MinosIllyrien答案是正確的,但事實並非如此。 但是,我認為我可以解決問題。 如果您認為我失敗了,請隨時發表評論。

這是我自己的解釋:

假設您有三類人:

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

在一個公平的世界中,會發生什么? 首先,通過MITY,然后通過AIAY,輪到您在隊列中的前面,現在輪到您了(無論有多少LITY:公平地說,但不要太多)。

但是在您的世界中,每次MITY通過時,他/她都會更改AIAY的順序。 直到最后一個MITY通過都沒關系。 如果他/她在您之前,那沒問題。 但是,如果他/她在您后面,您和他之前的所有AIAY都將移到后方。 因此,這之后的AIAY在您之前,而AIAY在您之前的位置仍然在您之前。 因此,您之后剩下的唯一AIAY是您和最后一個MITY之間的AIAY。

編輯:問題是MITY的順序:它們不是按位置(在MinosIllyrien答案中的問題)排序,而是按優先級和位置排序。 上面的部分沒有缺陷,並且保持不變。

如果需要輸出排序的作業,則不需要特定的數據結構。 這是一種具有簡單鏈表(或兩個數組列表)的算法:一個用於存儲作業,一個用於標記已執行的作業)

假設作業列表不為空。

  1. 令Ps =從最大到最小的有序優先級集合
  2. 讓last_pos = 0
  3. 令P = Ps.pop()和start_pos = last_pos
  4. 從P的start_pos到last_pos執行(並刪除)所有優先級為P的作業(從末尾到后退)
  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)。

如果您實際上想模擬打印機的行為,我認為正確的方法是使用一個鏈表(或一個數組加上一個整數,以便在您反復遍歷它時跟蹤您的當前位置) 加上優先級隊列。 每當發現鏈表頂部的值與優先級隊列中的最高值匹配時,便將其從兩個隊列中刪除。 這種方法需要最壞情況下的On 2 )時間。

但是,如果您只想查找分鍾數,則可以在最壞情況下的On log m )時間進行操作,其中n是作業總數, m是不同優先級的數目。 (M≤N,這樣也有最壞情況下O(n log n)的時間。)這里有一種方法:

  1. 構建一個TreeMap<Integer, ArrayList<Integer>>將每個優先級值映射到具有該優先級的作業隊列索引列表。
    • 這需要On log m )時間,其中m是隊列中不同優先級的數量。
    • 作為一個小的優化,我們可以跳過任何小於感興趣工作的優先級值。
  2. 初始化int lastPos = -1int numJobsCompleted = 0
  3. 遍歷映射中的值(=作業隊列索引列表),從最高優先級值開始,然后朝着我們感興趣的作業的優先級值進行工作。對於每個索引列表,找到如果有,最大的工作隊列索引(=列表元素)小於lastPos 否則,采用最大的工作隊列索引(=列表元素)。 無論哪種情況,都將lastPos更新lastPos作業隊列索引,並更新numJobsCompleted以添加作業隊列索引列表的大小。
    • 這里的想法是,當我們檢查了所有大於或等於某個值的優先級時, lastPos指向作業隊列中最新完成的項的索引; 這樣我們就可以處理下一個優先級的作業,該作業從索引lastPos+1開始,到索引lastPos-1結束(當然,在n處環繞)。
    • 如果我們在數組列表上使用線性搜索,則需要最壞情況的On )。
    • 作為一個小的優化,我們可以在數組列表上使用二進制搜索。
    • 作為一個小的優化,我們可以從掃描優先級最低的值開始,該優先級值大於或等於我們感興趣的作業的優先級值,並且在其數組列表中恰好有一個作業隊列索引。 專業版
  4. 當我們達到我們感興趣的作業的優先級值時,我們只需要找到lastPos和我們感興趣的作業的索引之間的作業索引的數量,並相應地更新numJobsCompleted 這可以通過線性搜索(最壞情況On ))或二進制搜索(最壞情況O (log n ))來完成。

這是錯誤的-我在底部寫下了原因:

[[瀏覽列表。 在索引之前,將具有相同優先級或高於您的優先級的每個元素都算作索引。 在索引之后,僅將優先級比您的元素嚴格高的元素算為一個,直到最后一個優先級更高的索引為止。 在該索引之后,繼續將優先級與您相同的所有元素都計為一個。 這樣可以為您提供要在元素之前打印的元素數量,因此請為您自己的元素增加一分鍾的時間。

我希望這有幫助。

編輯:

澄清一下:讓我們根據優先級重命名隊列中的所有元素。 l較低,e等於,h較高。 w是通緝文件。 問題中的順序將是:

w e h e e e

我們從計算w之前的eh的數目開始,因為它們將在w之前打印。 (e被移動到w之前的隊列的后面, h被首先處理。)在此示例中, w之前沒有元素,因此我們將其計數為0。

w之后,我們僅計算h ,因為它們被移到了隊列的最前面。 在此示例中只有1個。

最后,我們數數E'W¯¯是最后小時后(如果有任何小時W),因為W是后面移動這些電子的。 一共有3個,所以總共我們之前有4個打印作業。 添加我們自己的打印作業,我們總共可以得到5個作業/分鍾。

為此,我們需要遍歷列表兩次,一次查找最后一個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之后,我們在最后一個h之后計算3 h和0 e 這意味着將在我們自己之前打印三個元素(9、8和7),而不會打印el (2和1)。

總共,我們算出了4個印刷在我們自己之前的元素,我們的印刷是第5個。

我沒有考慮過要素可能要經過幾輪。 當較高優先級的工作按降序排列時,上述情況成立,但是反正例是(ru'h)指出的(1',2,1,3)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM