由於前面工人完成的任務,後面的工人也可以完成,因此可以使用 雙指標(Two Pointers) 的方式來找到每個工人可以完成的工作。 i 指向當前可以完成的難度最大的工作、j 指向當前枚舉的工人、mx 紀錄當前工人可以完成的最大利潤,範例中直接使用 w 來枚舉工人。
在遍歷每個工人時,將 i 移動到最後一個可以完成的工作,並在每次移動時將 mx 更新為當前工人可以完成的最大利潤,最後將 mx 加到答案中。
複雜度分析
時間複雜度:O(nlogn+mlogm) ,主要為排序的時間複雜度,雙指標分別最多移動 n 和 m 次。
空間複雜度:O(n) ,用於存儲排序後的工作。
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: defmaxProfitAssignment(self, difficulty: List[int], profit: List[int], worker: List[int]) -> int: n, m = len(difficulty), len(worker) tasks = sorted(zip(difficulty, profit)) worker.sort() ans, i, mx = 0, 0, 0 # for j, w in enumerate(worker): for w in worker: while i < n and tasks[i][0] <= w: # find the last task that can be done mx = max(mx, tasks[i][1]) # max profit i += 1 ans += mx return ans
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution { public: intmaxProfitAssignment(vector<int>& difficulty, vector<int>& profit, vector<int>& worker){ int n = difficulty.size(), m = worker.size(); vector<pair<int, int>> tasks; for (int i = 0; i < n; i++) tasks.push_back({difficulty[i], profit[i]}); sort(tasks.begin(), tasks.end()); sort(worker.begin(), worker.end()); int ans = 0, i = 0, mx = 0; for (int w : worker) { while (i < n && tasks[i].first <= w) { // find the last task that can be done mx = max(mx, tasks[i].second); // max profit i++; } ans += mx; } return ans; } };
但到這裡會有另外一個問題,我們需要在每次二分搜尋時,找到最大的利潤。這裡是預先處理一個額外的陣列 max_profit 來存儲前 i 個工作的最大利潤,這樣在每次二分搜尋後,只需要 O(1) 的時間複雜度即可找到最大利潤。
複雜度分析
時間複雜度:O(nlogn+mlogn) ,排序的時間複雜度為 O(nlogn) ,每次二分搜尋的時間複雜度為 O(logn) ,總共有 m 次二分搜尋。
空間複雜度:O(n) ,用於存儲排序後的工作,以及前 i 個工作的最大利潤。
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: defmaxProfitAssignment(self, difficulty: List[int], profit: List[int], worker: List[int]) -> int: n, m = len(difficulty), len(worker) tasks = sorted(zip(difficulty, profit)) # sort by difficulty max_profit = [0] * (n) # max_profit[i] = max profit of tasks[0:i+1] max_profit[0] = tasks[0][1] for i inrange(1, n): max_profit[i] = max(max_profit[i-1], tasks[i][1]) ans = 0 for ability in worker: idx = bisect_right(tasks, (ability, float("inf"))) - 1# find the last task that can be done ans += max_profit[idx] if idx >= 0else0 return ans
classSolution { public: intmaxProfitAssignment(vector<int>& difficulty, vector<int>& profit, vector<int>& worker){ int n = difficulty.size(), m = worker.size(); vector<pair<int, int>> tasks; for (int i = 0; i < n; i++) tasks.push_back({difficulty[i], profit[i]}); sort(tasks.begin(), tasks.end()); // sort by difficulty vector<int> max_profit(n, 0); // max_profit[i] = max profit of tasks[0:i+1] max_profit[0] = tasks[0].second; for (int i = 1; i < n; i++) { max_profit[i] = max(max_profit[i-1], tasks[i].second); } int ans = 0; for (int w : worker) { int idx = upper_bound(tasks.begin(), tasks.end(), make_pair(w, INT_MAX)) - tasks.begin() - 1; // find the last task that can be done ans += idx >= 0 ? max_profit[idx] : 0; } return ans; } };
寫在最後
Cover photo is generated by @たろたろ, thanks for their work!