題目描述:給定整數陣列 nums,對每個位置 i,計算 i 右側有多少個元素嚴格小於 nums[i],並以陣列形式返回。
解題思路:使用帶索引追蹤的合併排序(Merge Sort with Index Tracking)。建立一個 (value, originalIndex) 的 pair 陣列,在合併排序的「合併」步驟中:當右半部分的某個元素被先放入結果(即右邊元素 < 左邊元素),代表右邊這個元素比左半部分所有「尚未處理的」元素小。此時記錄「目前有多少右半元素已搶先放入」的計數 rightCount,等到左半部分元素被放入時,counts[原始索引] += rightCount。整個過程中透過原始索引映射,最終 counts 陣列即為所求。
時間複雜度:O(n log n) — 合併排序遞迴深度 O(log n),每層合併共處理 O(n) 個元素,故總體 O(n log n)。
空間複雜度:O(n) — 遞迴呼叫棧 O(log n),每次合併的臨時陣列最大 O(n),整體空間為 O(n)。
1. Build indexed array of (value, originalIndex) pairs.
2. Call mergeSort(indexed, 0, n-1, counts).
3. In mergeSort(arr, left, right):
a. If left >= right, return.
b. mid = (left + right) / 2.
c. Recurse on left half and right half.
d. Call merge(arr, left, mid, right).
4. In merge(arr, left, mid, right):
a. i = left, j = mid+1, rightCount = 0.
b. While both halves have elements:
- If arr[j].value < arr[i].value: place arr[j], rightCount++.
- Else: counts[arr[i].index] += rightCount; place arr[i].
c. Flush remaining left elements: counts[arr[i].index] += rightCount.
d. Flush remaining right elements.
e. Copy tmp back to arr[left..right].
5. Return counts.方法一:合併排序 + 索引追蹤(本題主解)O(n log n) 在合併過程中統計右半元素被提前放置的數量,映射回原始索引記錄答案。時間 O(n log n),空間 O(n),實作相對直觀。
方法二:Binary Indexed Tree(Fenwick Tree)O(n log n) 從右往左掃描,將 nums[i] 座標壓縮後在 BIT 上點更新,查詢前綴和即為比 nums[i] 小的元素數量。時間 O(n log n),空間 O(n),常數較小且程式碼簡潔。
方法三:平衡 BST / 有序集合 O(n log n) 從右往左掃描,用 std::multiset 或 policy-based order_statistics_tree,插入每個元素並查詢小於當前值的元素個數(order_of_key)。時間 O(n log n),但 C++ 標準庫的 multiset 不直接支援排名查詢,需使用 PBDS 擴充。