Welcome to Subscribe On Youtube

Question

Formatted question description: https://leetcode.ca/all/315.html

Given an integer array nums, return an integer array counts where counts[i] is the number of smaller elements to the right of nums[i].

 

Example 1:

Input: nums = [5,2,6,1]
Output: [2,1,1,0]
Explanation:
To the right of 5 there are 2 smaller elements (2 and 1).
To the right of 2 there is only 1 smaller element (1).
To the right of 6 there is 1 smaller element (1).
To the right of 1 there is 0 smaller element.

Example 2:

Input: nums = [-1]
Output: [0]

Example 3:

Input: nums = [-1,-1]
Output: [0,0]

 

Constraints:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

Algorithm

You can start traversing from the right, and keep putting the traversed numbers into another sort array, and store this sort array in ascending order, So, if you are looking for a few smaller numbers to the right of the current value, then you have to find the position where the current value should be placed in the sort array (In order to improve efficiency, use the binary search method to determine where the current value should be placed), that is, there are several smaller numbers on the right.

example:

nums: [5,2,6,1] When i = 3, nums[i] =1, sort[0]=nums[i];

0 1 2 3     <= sort[] index
1           <= sort[] value

When i = 2, nums[i] = 6, by using the dichotomy search in sort (currently only element 1), it is found that 6 should be inserted after 1, [1,6], ie index=1, sort[index] =nums[i]; So the number of numbers smaller than it on the right of the current value 6 is index=1

0 1 2 3
1 6

When i = 1, nums[i] = 2, by using the dichotomy search in sort (currently only elements 1, 6), it is found that 2 should be inserted after 1, [1,2,6], ie index=1, sort[index]=nums[i]; So the number of numbers smaller than it on the right side of the current value 2 is index=1

0 1 2 3
1 2 6

When i = 0 and nums[i] = 5, by using the dichotomy search in sort (currently only elements 1, 2, 6), it is found that 5 should be inserted after 2, [1,2,5,6], that is index=2, sort[index]=nums[i]; So the number of numbers smaller than it on the right of the current value of 5 is index=2

0 1 2 3
1 2 5 6

Then, the result is Output: [2,1,1,0].

Code

Appended Solution 2: Translated Upstream Explanation

The line segment tree divides the entire interval into multiple discontinuous sub-intervals, and the number of sub-intervals does not exceed log(width). To update the value of an element, you only need to update log(width) intervals, and these intervals are all included in a large interval containing the element.

  • Each node of the line segment tree represents an interval;
  • The line segment tree has a unique root node, and the interval represented is the entire statistical range, such as [1, N];
  • Each leaf node of the line segment tree represents a meta-interval [x, x] of length 1;
  • For each internal node [l, r], its left son is [l, mid] and its right son is [mid + 1, r], where mid = ⌊(l + r) / 2⌋ (that is, rounded down).
  • import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    public class Count_of_Smaller_Numbers_After_Self {
    
        public static void main(String[] args) {
            Count_of_Smaller_Numbers_After_Self out = new Count_of_Smaller_Numbers_After_Self();
            Solution s = out.new Solution();
    
            System.out.println(s.countSmaller(new int[]{5,2,6,1}));
        }
    
        class Solution {
            public List<Integer> countSmaller(int[] nums) {
    
                List<Integer> result = new ArrayList<>();
                List<Integer> sorted = new ArrayList<>();
    
                if (nums == null || nums.length == 0) {
                    return result;
                }
    
                for (int i = nums.length - 1; i >= 0; i--) {
    
                    // binary search for current pos, reference: Arrays.binarySearch()
                    int left = 0;
                    int right = sorted.size();
                    while (left < right) {
                        int mid = left + (right - left) / 2;
                        if (nums[i] <= sorted.get(mid)) {
                            right = mid;
                        } else {
                            left = mid + 1;
                        }
                    }
    
                    // now nums[i] should be placed at index left
                    sorted.add(left, nums[i]); // @note: equal to .insert()
                    result.add(0, left); // @note: insert to 1st node,因为是倒序scan array
                }
    
                return result;
            }
        }
    }
    
    ############
    
    class Solution {
        public List<Integer> countSmaller(int[] nums) {
            Set<Integer> s = new HashSet<>();
            for (int v : nums) {
                s.add(v);
            }
            List<Integer> alls = new ArrayList<>(s);
            alls.sort(Comparator.comparingInt(a -> a));
            int n = alls.size();
            Map<Integer, Integer> m = new HashMap<>(n);
            for (int i = 0; i < n; ++i) {
                m.put(alls.get(i), i + 1);
            }
            BinaryIndexedTree tree = new BinaryIndexedTree(n);
            LinkedList<Integer> ans = new LinkedList<>();
            for (int i = nums.length - 1; i >= 0; --i) {
                int x = m.get(nums[i]);
                tree.update(x, 1);
                ans.addFirst(tree.query(x - 1));
            }
            return ans;
        }
    }
    
    class BinaryIndexedTree {
        private int n;
        private int[] c;
    
        public BinaryIndexedTree(int n) {
            this.n = n;
            c = new int[n + 1];
        }
    
        public void update(int x, int delta) {
            while (x <= n) {
                c[x] += delta;
                x += lowbit(x);
            }
        }
    
        public int query(int x) {
            int s = 0;
            while (x > 0) {
                s += c[x];
                x -= lowbit(x);
            }
            return s;
        }
    
        public static int lowbit(int x) {
            return x & -x;
        }
    }
    
    
    // Solution 2
    class Solution {
        public List<Integer> countSmaller(int[] nums) {
            Set<Integer> s = new HashSet<>();
            for (int v : nums) {
                s.add(v);
            }
            List<Integer> alls = new ArrayList<>(s);
            alls.sort(Comparator.comparingInt(a -> a));
            int n = alls.size();
            Map<Integer, Integer> m = new HashMap<>(n);
            for (int i = 0; i < n; ++i) {
                m.put(alls.get(i), i + 1);
            }
            SegmentTree tree = new SegmentTree(n);
            LinkedList<Integer> ans = new LinkedList<>();
            for (int i = nums.length - 1; i >= 0; --i) {
                int x = m.get(nums[i]);
                tree.modify(1, x, 1);
                ans.addFirst(tree.query(1, 1, x - 1));
            }
            return ans;
        }
    }
    
    class Node {
        int l;
        int r;
        int v;
    }
    
    class SegmentTree {
        private Node[] tr;
    
        public SegmentTree(int n) {
            tr = new Node[4 * n];
            for (int i = 0; i < tr.length; ++i) {
                tr[i] = new Node();
            }
            build(1, 1, n);
        }
    
        public void build(int u, int l, int r) {
            tr[u].l = l;
            tr[u].r = r;
            if (l == r) {
                return;
            }
            int mid = (l + r) >> 1;
            build(u << 1, l, mid);
            build(u << 1 | 1, mid + 1, r);
        }
    
        public void modify(int u, int x, int v) {
            if (tr[u].l == x && tr[u].r == x) {
                tr[u].v += v;
                return;
            }
            int mid = (tr[u].l + tr[u].r) >> 1;
            if (x <= mid) {
                modify(u << 1, x, v);
            } else {
                modify(u << 1 | 1, x, v);
            }
            pushup(u);
        }
    
        public void pushup(int u) {
            tr[u].v = tr[u << 1].v + tr[u << 1 | 1].v;
        }
    
        public int query(int u, int l, int r) {
            if (tr[u].l >= l && tr[u].r <= r) {
                return tr[u].v;
            }
            int mid = (tr[u].l + tr[u].r) >> 1;
            int v = 0;
            if (l <= mid) {
                v += query(u << 1, l, r);
            }
            if (r > mid) {
                v += query(u << 1 | 1, l, r);
            }
            return v;
        }
    }
    
    
  • // OJ: https://leetcode.com/problems/count-of-smaller-numbers-after-self/
    // Time: O(NlogN)
    // Space: O(N)
    class Solution {
        vector<int> id, tmp, ans;
        void solve(vector<int> &A, int begin, int end) {
            if (begin + 1 >= end) return;
            int mid = (begin + end) / 2, i = begin, j = mid, k = begin;
            solve(A, begin, mid);
            solve(A, mid, end);
            for (; i < mid; ++i) {
                while (j < end && A[id[j]] < A[id[i]]) {
                    tmp[k++] = id[j++];
                }
                ans[id[i]] += j - mid;
                tmp[k++] = id[i];
            }
            for (; j < end; ++j) tmp[k++] = id[j];
            for (int i = begin; i < end; ++i) id[i] = tmp[i];
        }
    public:
        vector<int> countSmaller(vector<int>& A) {
            int N = A.size();
            id.assign(N, 0);
            tmp.assign(N, 0);
            ans.assign(N, 0);
            iota(begin(id), end(id), 0);
            solve(A, 0, N);
            return ans;
        }
    };
    
    
    // Solution 2
    class Node {
    public:
        int l;
        int r;
        int v;
    };
    
    class SegmentTree {
    public:
        vector<Node*> tr;
    
        SegmentTree(int n) {
            tr.resize(4 * n);
            for (int i = 0; i < tr.size(); ++i) tr[i] = new Node();
            build(1, 1, n);
        }
    
        void build(int u, int l, int r) {
            tr[u]->l = l;
            tr[u]->r = r;
            if (l == r) return;
            int mid = (l + r) >> 1;
            build(u << 1, l, mid);
            build(u << 1 | 1, mid + 1, r);
        }
    
        void modify(int u, int x, int v) {
            if (tr[u]->l == x && tr[u]->r == x) {
                tr[u]->v += v;
                return;
            }
            int mid = (tr[u]->l + tr[u]->r) >> 1;
            if (x <= mid)
                modify(u << 1, x, v);
            else
                modify(u << 1 | 1, x, v);
            pushup(u);
        }
    
        void pushup(int u) {
            tr[u]->v = tr[u << 1]->v + tr[u << 1 | 1]->v;
        }
    
        int query(int u, int l, int r) {
            if (tr[u]->l >= l && tr[u]->r <= r) return tr[u]->v;
            int mid = (tr[u]->l + tr[u]->r) >> 1;
            int v = 0;
            if (l <= mid) v += query(u << 1, l, r);
            if (r > mid) v += query(u << 1 | 1, l, r);
            return v;
        }
    };
    
    class Solution {
    public:
        vector<int> countSmaller(vector<int>& nums) {
            unordered_set<int> s(nums.begin(), nums.end());
            vector<int> alls(s.begin(), s.end());
            sort(alls.begin(), alls.end());
            unordered_map<int, int> m;
            int n = alls.size();
            for (int i = 0; i < n; ++i) m[alls[i]] = i + 1;
            SegmentTree* tree = new SegmentTree(n);
            vector<int> ans(nums.size());
            for (int i = nums.size() - 1; i >= 0; --i) {
                int x = m[nums[i]];
                tree->modify(1, x, 1);
                ans[i] = tree->query(1, 1, x - 1);
            }
            return ans;
        }
    };
    
    
    
    // Solution 3
    class Solution {
    private:
        vector<int> rightSmallerCounts;
        vector<pair<int, int>> buffer;
    
        void combineArrays(
            vector<pair<int, int>>& numsIndices, int leftBound, int splitIdx, int rightBound) {
            // Left side array = numsIndices[leftBound: splitIdx].
            // Right side array = numsIndices[splitIdx: rightBound + 1].
            int leftIdx = leftBound, rightIdx = splitIdx;
            int bufferIdx = leftBound;
    
            while (leftIdx < splitIdx && rightIdx <= rightBound) {
                if (numsIndices[leftIdx].first <= numsIndices[rightIdx].first) {
                    // Iterated left side element finalizes its right smaller count.
                    int leftNumIdx = numsIndices[leftIdx].second;
                    rightSmallerCounts[leftNumIdx] += rightIdx - splitIdx;
    
                    buffer[bufferIdx++] = numsIndices[leftIdx++];
                }
    
                else
                    buffer[bufferIdx++] = numsIndices[rightIdx++];
            }
    
            while (leftIdx < splitIdx) {
                // Iterated left side element finalizes its right smaller count.
                int leftNumIdx = numsIndices[leftIdx].second;
                rightSmallerCounts[leftNumIdx] += rightIdx - splitIdx;
    
                buffer[bufferIdx++] = numsIndices[leftIdx++];
            }
    
            while (rightIdx <= rightBound)
                buffer[bufferIdx++] = numsIndices[rightIdx++];
    
            for (int idx = leftBound; idx <= rightBound; idx++)
                numsIndices[idx] = buffer[idx]; // Put buffer data back to original array.
        }
    
        void mergeSort(vector<pair<int, int>>& numsIndices, int leftBound, int rightBound) {
            if (leftBound == rightBound) return; // Single element.
    
            // Plus 1: ensure splitIdx > leftBound.
            int splitIdx = (leftBound + rightBound + 1) / 2;
    
            mergeSort(numsIndices, leftBound, splitIdx - 1);
            mergeSort(numsIndices, splitIdx, rightBound);
    
            combineArrays(numsIndices, leftBound, splitIdx, rightBound);
        }
    
    public:
        vector<int> countSmaller(vector<int>& nums) {
            buffer.resize(nums.size()); // Against memory explosions.
    
            vector<pair<int, int>> numsIndices(nums.size());
            for (int idx = 0; idx < nums.size(); idx++)
                numsIndices[idx] = {nums[idx], idx};
    
            rightSmallerCounts.assign(nums.size(), 0);
            mergeSort(numsIndices, 0, nums.size() - 1);
            return rightSmallerCounts;
        }
    };
    
    
  • '''
    bisect: maintaining a list in sorted order without having to sort the list after each insertion.
    https://docs.python.org/3/library/bisect.html
    
    bisect.bisect_left()
    Locate the insertion point for x in a to maintain sorted order.
    
    bisect.bisect_right() or bisect.bisect()
    Similar to bisect_left(), but returns an insertion point which comes after (to the right of) any existing entries of x in a.
    
    
    bisect.insort_left(a, x, lo=0, hi=len(a), *, key=None)
    Insert x in a in sorted order.
    Keep in mind that the O(log n) search is dominated by the slow O(n) insertion step.
    
    
    bisect.insort_right(a, x, lo=0, hi=len(a), *, key=None)
    bisect.insort(a, x, lo=0, hi=len(a), *, key=None)
    Similar to insort_left(), but inserting x in a after any existing entries of x.
    
    
    >>> import bisect
    >>> bisect.bisect_left([1,2,3], 2)
    1
    >>> bisect.bisect_right([1,2,3], 2)
    2
    
    >>> a = [1, 1, 1, 2, 3]
    >>> bisect.insort_left(a, 1.0)
    >>> a
    [1.0, 1, 1, 1, 2, 3]
    
    >>> a = [1, 1, 1, 2, 3]
    >>> bisect.insort_right(a, 1.0)
    >>> a
    [1, 1, 1, 1.0, 2, 3]
    
    >>> a = [1, 1, 1, 2, 3]
    >>> bisect.insort(a, 1.0)
    >>> a
    [1, 1, 1, 1.0, 2, 3]
    '''
    
    import bisect
    
    class Solution(object):
      def countSmaller(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        ans = []
        bst = []
        for num in reversed(nums):
          idx = bisect.bisect_left(bst, num)
          ans.append(idx)
          bisect.insort(bst, num)
        return ans[::-1]
    
    ############
    
    class BinaryIndexedTree:
        def __init__(self, n):
            self.n = n
            self.c = [0] * (n + 1)
    
        @staticmethod
        def lowbit(x):
            return x & -x
    
        def update(self, x, delta):
            while x <= self.n:
                self.c[x] += delta
                x += BinaryIndexedTree.lowbit(x)
    
        def query(self, x):
            s = 0
            while x > 0:
                s += self.c[x]
                x -= BinaryIndexedTree.lowbit(x)
            return s
    
    
    class Solution:
        def countSmaller(self, nums: List[int]) -> List[int]:
            alls = sorted(set(nums))
            m = {v: i for i, v in enumerate(alls, 1)}
            tree = BinaryIndexedTree(len(m))
            ans = []
            for v in nums[::-1]:
                x = m[v]
                tree.update(x, 1)
                ans.append(tree.query(x - 1))
            return ans[::-1]
    
    
    # Solution 2
    class Node:
        def __init__(self):
            self.l = 0
            self.r = 0
            self.v = 0
    
    
    class SegmentTree:
        def __init__(self, n):
            self.tr = [Node() for _ in range(n << 2)]
            self.build(1, 1, n)
    
        def build(self, u, l, r):
            self.tr[u].l = l
            self.tr[u].r = r
            if l == r:
                return
            mid = (l + r) >> 1
            self.build(u << 1, l, mid)
            self.build(u << 1 | 1, mid + 1, r)
    
        def modify(self, u, x, v):
            if self.tr[u].l == x and self.tr[u].r == x:
                self.tr[u].v += v
                return
            mid = (self.tr[u].l + self.tr[u].r) >> 1
            if x <= mid:
                self.modify(u << 1, x, v)
            else:
                self.modify(u << 1 | 1, x, v)
            self.pushup(u)
    
        def query(self, u, l, r):
            if self.tr[u].l >= l and self.tr[u].r <= r:
                return self.tr[u].v
            mid = (self.tr[u].l + self.tr[u].r) >> 1
            v = 0
            if l <= mid:
                v += self.query(u << 1, l, r)
            if r > mid:
                v += self.query(u << 1 | 1, l, r)
            return v
    
        def pushup(self, u):
            self.tr[u].v = self.tr[u << 1].v + self.tr[u << 1 | 1].v
    
    
    class Solution:
        def countSmaller(self, nums: List[int]) -> List[int]:
            s = sorted(set(nums))
            m = {v: i for i, v in enumerate(s, 1)}
            tree = SegmentTree(len(s))
            ans = []
            for v in nums[::-1]:
                x = m[v]
                ans.append(tree.query(1, 1, x - 1))
                tree.modify(1, x, 1)
            return ans[::-1]
    
    
    
    # Solution 3
    class Solution:
        def countSmaller(self, nums: list[int]) -> list[int]:
            self.right_smaller_counts = [0] * len(nums)
    
            nums_indices = [(num, idx) for idx, num in enumerate(nums)]
            self.merge_sort(nums_indices)
    
            return self.right_smaller_counts
    
        def combine_arrays(
            self,
            left_nums_indices: list[tuple[int, int]],
            right_nums_indices: list[tuple[int, int]],
        ) -> list[tuple[int, int]]:
            merged_nums_indices: list[tuple[int, int]] = []
            left_idx, right_idx = 0, 0
    
            while left_idx < len(left_nums_indices) and right_idx < len(right_nums_indices):
                if left_nums_indices[left_idx][0] <= right_nums_indices[right_idx][0]:
                    # Iterated left side element finalizes its right smaller count.
                    left_num_idx = left_nums_indices[left_idx][1]
                    self.right_smaller_counts[left_num_idx] += right_idx
    
                    merged_nums_indices.append(left_nums_indices[left_idx])
                    left_idx += 1
                    continue
    
                merged_nums_indices.append(right_nums_indices[right_idx])
                right_idx += 1
    
            while left_idx < len(left_nums_indices):
                # Iterated left side element finalizes its right smaller count.
                left_num_idx = left_nums_indices[left_idx][1]
                self.right_smaller_counts[left_num_idx] += len(right_nums_indices)
    
                merged_nums_indices.append(left_nums_indices[left_idx])
                left_idx += 1
    
            while right_idx < len(right_nums_indices):
                merged_nums_indices.append(right_nums_indices[right_idx])
                right_idx += 1
    
            return merged_nums_indices
    
        def merge_sort(self, nums_indices: list[tuple[int, int]]) -> list[tuple[int, int]]:
            if len(nums_indices) == 1:
                return nums_indices  # Single element.
    
            split_idx = len(nums_indices) // 2
    
            left_nums_indices = self.merge_sort(nums_indices[:split_idx])
            right_nums_indices = self.merge_sort(nums_indices[split_idx:])
    
            return self.combine_arrays(left_nums_indices, right_nums_indices)
    
    
  • type BinaryIndexedTree struct {
    	n int
    	c []int
    }
    
    func newBinaryIndexedTree(n int) *BinaryIndexedTree {
    	c := make([]int, n+1)
    	return &BinaryIndexedTree{n, c}
    }
    
    func (this *BinaryIndexedTree) lowbit(x int) int {
    	return x & -x
    }
    
    func (this *BinaryIndexedTree) update(x, delta int) {
    	for x <= this.n {
    		this.c[x] += delta
    		x += this.lowbit(x)
    	}
    }
    
    func (this *BinaryIndexedTree) query(x int) int {
    	s := 0
    	for x > 0 {
    		s += this.c[x]
    		x -= this.lowbit(x)
    	}
    	return s
    }
    
    func countSmaller(nums []int) []int {
    	s := make(map[int]bool)
    	for _, v := range nums {
    		s[v] = true
    	}
    	var alls []int
    	for v := range s {
    		alls = append(alls, v)
    	}
    	sort.Ints(alls)
    	m := make(map[int]int)
    	for i, v := range alls {
    		m[v] = i + 1
    	}
    	ans := make([]int, len(nums))
    	tree := newBinaryIndexedTree(len(alls))
    	for i := len(nums) - 1; i >= 0; i-- {
    		x := m[nums[i]]
    		tree.update(x, 1)
    		ans[i] = tree.query(x - 1)
    	}
    	return ans
    }
    
    
    // Solution 2
    type Pair struct {
    	val   int
    	index int
    }
    
    var (
    	tmp   []Pair
    	count []int
    )
    
    func countSmaller(nums []int) []int {
    	tmp, count = make([]Pair, len(nums)), make([]int, len(nums))
    	array := make([]Pair, len(nums))
    	for i, v := range nums {
    		array[i] = Pair{val: v, index: i}
    	}
    	sorted(array, 0, len(array)-1)
    	return count
    }
    
    func sorted(arr []Pair, low, high int) {
    	if low >= high {
    		return
    	}
    	mid := low + (high-low)/2
    	sorted(arr, low, mid)
    	sorted(arr, mid+1, high)
    	merge(arr, low, mid, high)
    }
    
    func merge(arr []Pair, low, mid, high int) {
    	left, right := low, mid+1
    	idx := low
    	for left <= mid && right <= high {
    		if arr[left].val <= arr[right].val {
    			count[arr[left].index] += right - mid - 1
    			tmp[idx], left = arr[left], left+1
    		} else {
    			tmp[idx], right = arr[right], right+1
    		}
    		idx++
    	}
    	for left <= mid {
    		count[arr[left].index] += right - mid - 1
    		tmp[idx] = arr[left]
    		idx, left = idx+1, left+1
    	}
    	for right <= high {
    		tmp[idx] = arr[right]
    		idx, right = idx+1, right+1
    	}
    	// 排序
    	for i := low; i <= high; i++ {
    		arr[i] = tmp[i]
    	}
    }
    
    

All Problems

All Solutions