题目描述:
给出一个长度为 $n$ 的整数数组nums
,按要求返回一个新数组counts
。其中 counts[i]
的值表示nums[i]
右侧小于nums[i]
的元素数量。
数据范围:
$1\le n \le 10^5;-10^4\le nums[i]\le 10^4$
题解:
可以使用类似归并排序的二分操作,也可以直接使用线段树或者树状数组维护 $[1,max\_val]$ ,直接查询比当前值小的元素的个数,即前缀和 $[1,val-1]$ 。
由于数据有负的,可以使用离散化,使用 $unordered\_map$ 或者 $sort+unique+lower\_bound$ ,也可以不使用离散化,直接全都加上一个数,将负的转化为正的。
归并排序做法:
归并排序可以用来求逆序对有关的问题,明显也是逆序对,但是只是一边的逆序对。假设分成了 $[l, mid], [mid+1, right]$ 且两边都是有序的,令 $i = l,j=mid + 1$ 。
如果 $a[i] \le a[j]$ 那么说明这次该拿 $a[i]$ 放入 $tmp$ 数组了, $a[j]$ 前面的已经全放入 $tmp$ 数组了,因此存在 $j - 1 - mid - 1 + 1 = j - mid - 1$ 个比 $a[i]$ 小的元素,更新答案。注意当右侧为空时,说明右侧的全部元素都比 $a[i]$ 小,记得更新答案。
从另一个角度,如果 $a[i] > a[j]$ ,那么说明这次应该拿 $a[j]$ 了, $a[j]$ 比 $a[i]$ 以及后面的都小,因此对后面的元素都要贡献答案。但是这时需要遍历 $a[i]$ 后面的元素,因此不适合。如果是求逆序对,那么就可以直接加上 $mid - i + 1$ 。而且当右侧为空的时候也不用继续更新答案了,因为贡献前面已经加上了。
代码:
unordered_map
离散化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| class Solution { public: const static int maxn = 1e5 + 10; const static int maxm = 1e5 + 10; const static int INF = 0x3f3f3f3f; struct Tree { vector<int> c; int max_size; Tree(int n) : c(n + 1), max_size(n) {} int lowbit(int x) { return x & -x; } void add(int index, int value) { while (index <= max_size) { c[index] += value; index += lowbit(index); } } int query(int index) { int ans = 0; while (index >= 1) { ans += c[index]; index -= lowbit(index); } return ans; } };
unordered_map<int, int> mp; vector<int> countSmaller(vector<int> &nums) { int n = nums.size(); vector<int> nums_b = nums; sort(nums_b.begin(), nums_b.end()); int tmp = 0; for (int i = 0; i < n; ++i) { if (!mp.count(nums_b[i])) mp[nums_b[i]] = ++tmp; } int max_size = mp[nums_b[n - 1]]; Tree tree(max_size); vector<int> ret(n, 0); for (int i = n - 1; i >= 0; --i) { ret[i] = tree.query(mp[nums[i]] - 1); tree.add(mp[nums[i]], 1); } return ret; } };
|
sort + unique + lower_bound
离散化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| class Solution { public: const static int maxn = 1e5 + 10; const static int maxm = 1e5 + 10; const static int INF = 0x3f3f3f3f; struct Tree { vector<int> c; int max_size; Tree(int n) : c(n + 1), max_size(n) {} int lowbit(int x) { return x & -x; } void add(int index, int value) { while (index <= max_size) { c[index] += value; index += lowbit(index); } } int query(int index) { int ans = 0; while (index >= 1) { ans += c[index]; index -= lowbit(index); } return ans; } };
vector<int> countSmaller(vector<int> &nums) { int n = nums.size(); vector<int> nums_b = nums; nums_b.emplace_back(-1e4 - 1); sort(nums_b.begin(), nums_b.end()); int max_size = unique(nums_b.begin(), nums_b.end()) - nums_b.begin(); for (int i = 0; i < n; ++i) { nums[i] = lower_bound(nums_b.begin(), nums_b.begin() + max_size, nums[i]) - nums_b.begin(); }
Tree tree(max_size); vector<int> ret(n, 0); for (int i = n - 1; i >= 0; --i) { ret[i] = tree.query(nums[i] - 1); tree.add(nums[i], 1); } return ret; } };
|
归并排序逆序对做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| class Solution { public: const static int maxn = 1e5 + 10; const static int maxm = 1e5 + 10; const static int INF = 0x3f3f3f3f; vector<pair<int, int>> tmp; vector<pair<int, int>> nums_p; void mix_merge(vector<int> &ans, vector<pair<int, int>> &nums, int l, int mid, int r) { int l1 = l, l2 = mid + 1, l3 = l; while (l1 <= mid && l2 <= r) { if (nums[l1].first <= nums[l2].first) { ans[nums[l1].second] += l2 - mid - 1; tmp[l3++] = nums[l1++]; } else { tmp[l3++] = nums[l2++]; } } while (l1 <= mid) { ans[nums[l1].second] += l2 - mid - 1; tmp[l3++] = nums[l1++]; } while (l2 <= r) tmp[l3++] = nums[l2++]; for (int i = l; i <= r; ++i) { nums[i] = tmp[i]; } }
void merge_sort(vector<int> &ans, vector<pair<int, int>> &nums, int l, int r) { if (l == r) return; int mid = (l + r) >> 1; merge_sort(ans, nums, l, mid); merge_sort(ans, nums, mid + 1, r); mix_merge(ans, nums, l, mid, r); }
vector<int> countSmaller(vector<int> &nums) { int n = nums.size(); tmp.resize(n); nums_p.resize(n); for (int i = 0; i < n; ++i) { nums_p[i] = {nums[i], i}; } vector<int> ans(n); merge_sort(ans, nums_p, 0, n - 1); return ans; } };
|