根據B中的執行順序查詢A中任務的執行時間
目標是確定在佇列A和B(大小均為N)給定的情況下,根據佇列B中的執行順序完成佇列A中任務所需的最小時間。
如果在佇列B頭部識別的任務也在佇列A頭部,則彈出此任務並執行。
如果在佇列B頭部發現的任務未在佇列A頭部找到,則從佇列A彈出當前任務並將其推送到末尾。
佇列中的每個推送和彈出操作花費一個時間單位,每個作業的完成時間固定。
為了解決這個問題,我們可以模擬按照佇列B給出的順序執行任務,同時跟蹤佇列A的當前狀態。對於佇列B中的每個任務,我們需要執行以下步驟:
檢查佇列B頭部任務是否與佇列A頭部任務匹配。
如果任務匹配,則透過從兩個佇列中彈出任務來執行任務。
如果任務不匹配,則從佇列A頭部彈出任務並將其推送到佇列A的尾部。
為每個推送和彈出操作將時間計數器加1。
虛擬碼
以下是execute_tasks函式的虛擬碼
function execute_tasks(A, B): time = 0 while B is not empty: if A[0] == B[0]: task = A.pop(0) B.pop(0) time = time + 1 else: task = A.pop(0) A.append(task) time = time + 1 return time
注意,這假設A和B都是表示佇列的列表(或陣列)。pop(0)方法刪除列表中的第一個元素並返回它,而append(task)方法將task新增到列表的末尾。在Python中,可以使用A[0]訪問列表A的第一個元素。非空比較檢查列表是否非空,while迴圈重複直到B為空。
Java實現
以下是上述虛擬碼的Java實現
示例
import java.util.ArrayList; import java.util.List; public class Main{ public static int execute_tasks(List<Integer> A, List<Integer> B) { int time = 0; while (!B.isEmpty()) { if (A.get(0).equals(B.get(0))) { int task = A.remove(0); B.remove(0); time++; } else { int task = A.remove(0); A.add(task); time++; } } return time; } public static void main(String args[]) { List<Integer> arrayList1 = new ArrayList<Integer>(); arrayList1.add(3); arrayList1.add(2); arrayList1.add(1); List<Integer> arrayList2 = new ArrayList<Integer>(); arrayList2.add(1); arrayList2.add(2); arrayList2.add(3); int time = Main.execute_tasks(arrayList1, arrayList2); System.out.println("Time Taken: "+time); } }
輸出
Time Taken: 6
此演算法的時間複雜度為O(N^2),因為我們可能需要為佇列B中的每個任務迭代佇列A中的所有任務。但是,由於輸入大小較小(N <= 100),因此該演算法對於實際應用來說應該足夠高效。
提供的解決方案中execute_tasks()方法的時間複雜度為O(N^2),其中N是佇列A和B的組合大小。這是因為在最壞情況下,我們可能需要對佇列B中的每個任務重複該過程。對佇列A執行的操作(彈出和追加)具有O(1)的時間複雜度,但迭代佇列A中的所有任務可能具有O(N)的時間複雜度。
該函式的空間複雜度為O(N),因為必須將列表A和B儲存在記憶體中。記憶體使用量取決於任務總數,而不是它們的執行順序。時間計數器和當前任務也儲存在一些常量大小的變數中,但它們對整體空間複雜度的影響最小。
使用Java Map資料結構
您可以透過使用Map資料結構儲存佇列A中任務的索引來最佳化此程式碼。這將允許我們快速查詢任務在A中的位置,而無需每次都搜尋整個佇列。
Java實現
示例
import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.HashMap; public class Demo{ public static int execute_tasks(List<Integer> A, List<Integer> B) { int time = 0; Map<Integer, Integer> taskIndex = new HashMap<>(); for (int i = 0; i < A.size(); i++) { taskIndex.put(A.get(i), i); } int nextIndex = 0; for (int i = 0; i < B.size(); i++) { int task = B.get(i); if (taskIndex.containsKey(task)) { int index = taskIndex.get(task); int numMoves = index - nextIndex; A.remove(index); A.add(0, task); time += numMoves + 1; nextIndex++; } else { A.remove(0); A.add(task); time += 2; } } return time; } public static void main(String args[]) { List<Integer> arrayList1 = new ArrayList<Integer>(); arrayList1.add(3); arrayList1.add(2); arrayList1.add(1); List<Integer> arrayList2 = new ArrayList<Integer>(); arrayList2.add(1); arrayList2.add(2); arrayList2.add(3); int time = Demo.execute_tasks(arrayList1, arrayList2); System.out.println("Time Taken: "+time); } }
輸出
Time Taken: 3
taskIndex()對映用於儲存A中任務的索引。函式開頭的for迴圈透過迭代A的元素並存儲它們的索引來填充此對映。nextIndex()變數用於跟蹤B中下一個任務在A中預期的位置。
在B的for迴圈中,如果在A中找到B中的當前任務,我們使用taskIndex對映查詢其在A中的索引並計算將其移到佇列A頭部所需的移動次數。然後,我們將任務從其在A中的原始位置刪除,將其新增到A的頭部,並相應地更新時間和nextIndex。
如果在A中找不到B中的當前任務,我們只需刪除A頭部任務,將其新增到A尾部,並將時間加2。
在Python中使用對映
透過使用對映儲存A中任務的索引,我們將查詢任務位置的時間複雜度從O(N)降低到O(1),從而使整體時間複雜度為O(N),其中N是佇列的大小。由於使用了taskIndex對映,空間複雜度仍然是O(N)。
實現
示例
def min_time(A, B): time = 0 i = 0 A_set = set(A) for b in B: if b in A_set: while A[i] != b: i = (i+1) % len(A) time += 1 time += 1 i = (i+1) % len(A) else: time += 1 return time A = [3, 2, 1] B = [1, 2, 3] time = min_time(A, B); print("Time Taken: ",time);
輸出
Time Taken: 7