Approach
Sorting and greedy selection
For Count of Smaller Numbers After Self, the implementation first exposes a useful order, then scans that order while making locally justified choices.
- Choose the key that reveals the greedy or grouping structure.
- Sort the relevant records by that key.
- Scan in order, maintaining the invariant that makes each local choice safe.
Code notes
- 55 lines of C++ from the credited upstream file 315.cpp.
- The implementation visibly relies on sequence storage, hash lookup, ordered lookup.
- 4 loop blocks detected.
Complexity
Sorting is typically the dominant term unless the subsequent scan uses a more expensive nested operation.
Check the problem constraints before deciding whether this complexity will pass.
Use this to learn the idea, then write your own version.
1class FenwickTree {2 public:3 FenwickTree(int n) : sums(n + 1) {}4 5 void add(int i, int delta) {6 while (i < sums.size()) {7 sums[i] += delta;8 i += lowbit(i);9 }10 }11 12 int get(int i) const {13 int sum = 0;14 while (i > 0) {15 sum += sums[i];16 i -= lowbit(i);17 }18 return sum;19 }20 21 private:22 vector<int> sums;23 24 static inline int lowbit(int i) {25 return i & -i;26 }27};28 29class Solution {30 public:31 vector<int> countSmaller(vector<int>& nums) {32 vector<int> ans(nums.size());33 const unordered_map<int, int> ranks = getRanks(nums);34 FenwickTree tree(ranks.size());35 36 for (int i = nums.size() - 1; i >= 0; --i) {37 const int num = nums[i];38 ans[i] = tree.get(ranks.at(num) - 1);39 tree.add(ranks.at(num), 1);40 }41 42 return ans;43 }44 45 private:46 unordered_map<int, int> getRanks(const vector<int>& nums) {47 unordered_map<int, int> ranks;48 set<int> sorted(nums.begin(), nums.end());49 int rank = 0;50 for (const int num : sorted)51 ranks[num] = ++rank;52 return ranks;53 }54};55