315. Count of Smaller Numbers After Self


time: O(nlogn)
space: O(n)
這題認真去看可以發現, 其實主體就是 mergeSort, 但為什麼可以在 mergeSort 的過程中
達成 count 右邊比本身小的結果呢?
主要是要先利用一個 Item class, 來記錄原本的值和 index
還有利用一個 count 陣列, 來記錄最後的答案, 怎麼紀錄答案呢?
就是利用 Item class 裡面原本的值和 index
當第一個 while 時, 如果
merge 5, 2
1.
if (items[l].val > items[r].val) =>
a. 代表目前是逆序(左邊 大於 右邊), 所以要 右邊 要移到 左邊, 才會是 sorted, 以這來說就是 item[r++] 加到 temp
b. 但逆序也代表了一件事 => 右邊有一個數大於左邊, 所以 rightCount++
else 也就是 sorted, 那要做什麼呢? 就是要記錄結果到 count[] 陣列, 因為已經沒有右邊比左邊大的 case 了
a. 記錄結果到 count[] 陣列 .=> 這就要利用到 items[l].idx 了 so count[items[l.idx]] += rightCount
b. 把 l 目前內容加入, item[l++] 加到 temp
ex 5, 2 .=> 2, 5 ., rightCount++, 塞了 2 到 temp[0]

while (l <= mid && r <= right) {
if (items[l].val > items[r].val) {
// l > r, means move r to l, so insert r data to temp,
// and add rightcount , ex 5 2 => 2 5, but rightCount should++
rightCount++;
temp[tempIdx++] = items[r++];
} else {
// if l < r, it is sorted, ex: 2 5,
// cal count result(count[l index] += rightCnt),
// insert l data to temp
count[items[l].idx] += rightCount;
temp[tempIdx++] = items[l++];
}
}
第二個 while 就跟 第一個 while else 其實內容一樣 ( 因為是 l <= mid)
while (l <= mid) { // insert remained l data, and cal count, (insert l data means cal result!)
count[items[l].idx] += rightCount;
temp[tempIdx++] = items[l++];
}
ex 5 2 .=> 2, 5 之後, 還剩下 5, 所以塞 5 到 temp[1] .( while l <= mid
5 的 count+= rightCount, 也就是 count[0] += 1
接著是 merge 1, and merge 2,5

ex 2 .5 merge 1 時 =>
lowPtr . | hiPtr
2 . 5 . 1
=> 經歷之前第一個 while 後 => 1 2 5 .=> rightCount = 1
lowPtr . mid hiPtr
2 . 5 . 1
while (l <= mid ) .=> 所以 2, 5 (count[1], count[0])都要 += rightCount (因為有個小的1 到左邊啦


while (l <= mid) { // insert remained l data, and cal count, (insert l data means cal result!)
count[items[l].idx] += rightCount;
temp[tempIdx++] = items[l++];
}
while (r <= right) { // insert remained r data
temp[tempIdx++] = items[r++];
}
// finally put sorted temp data to items
for (int p = 0; p < temp.length; p++) {
items[left + p] = temp[p];
}
最後把 temp 結果(sort 的), 更新到原本 items 中
class Solution {
private class Item {
int val;
int idx;
public Item(int val, int idx) {
this.val = val;
this.idx = idx; // for count use
}
}
public List<Integer> countSmaller(int[] nums) {
int n = nums.length;
int[] count = new int[n];
Item[] items = new Item[n];
for (int i = 0; i < n; i++) {
items[i] = new Item(nums[i], i);
}
mergeSort(items, 0, n - 1, count);
List<Integer> result = new ArrayList<>();
for (int cnt : count) {
result.add(cnt);
}
return result;
}
private void mergeSort(Item[] items, int left, int right, int[] count) {
if (left >= right) return;
int mid = (right + left) >> 1;
mergeSort(items, left, mid, count);
mergeSort(items, mid + 1, right, count);
merge(items, left, mid, right, count);
}
private void merge(Item[] items, int left, int mid, int right, int[] count) {
Item[] temp = new Item[right - left + 1];
int tempIdx = 0;
int l = left;
int r = mid + 1;
int rightCount = 0;
while (l <= mid && r <= right) {
if (items[l].val > items[r].val) {
// l > r, means move r to l, so insert r data to temp,
// and add rightcount , ex 5 2 => 2 5, but rightCount should++
rightCount++;
temp[tempIdx++] = items[r++];
} else {
// if l < r, it is sorted, ex: 2 5,
// cal count result(count[l index] += rightCnt),
// insert l data to temp
count[items[l].idx] += rightCount;
temp[tempIdx++] = items[l++];
}
}
while (l <= mid) { // insert remained l data, and cal count, (insert l data means cal result!)
count[items[l].idx] += rightCount;
temp[tempIdx++] = items[l++];
}
while (r <= right) { // insert remained r data
temp[tempIdx++] = items[r++];
}
// finally put sorted temp data to items
for (int p = 0; p < temp.length; p++) {
items[left + p] = temp[p];
}
}
}
Last updated
Was this helpful?