solution_315

LeetCode Problem Description

You are given an integer array nums and you have to return a new counts array.The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].

Example:

Given nums = [5, 2, 6, 1]

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.

Return the array [2, 1, 1, 0].

Solution

At first, I try to directly compare all the elements n2 times just as the following code shows:

vector<int> Solution::countSmaller (vector<int> & nums) {
    vector<int> result (nums.size(), 0);
    int current = 0;
    for (vector<int>::iterator i = nums.begin(); i != nums.end(); i++) {
        for (vector<int>::iterator j = i; j != nums.end(); j++) {
            if (*j < *i) {
                result[current]++;
            }
        }
        current++;
    }
    return result;
}

However, it doesn’t statisfy the requirement of the problem. Then I get some idea from this method
which using the merge sort and the cost is nlog(n) . I will explain what I got from this solution. Here is the code of the solution:

class Solution {
public:
    vector<int> countSmaller (vector<int> & nums);

protected:
    void merge_countSmaller(vector<int>& indices, int first, int last, 
                            vector<int>& results, vector<int>& nums) {
        int count = last - first;
        if (count > 1) {
            int step = count / 2;
            int mid = first + step;
            merge_countSmaller(indices, first, mid, results, nums);
            merge_countSmaller(indices, mid, last, results, nums);
            vector<int> tmp;
            tmp.reserve(count);
            int idx1 = first;
            int idx2 = mid;
            int semicount = 0;
            while ((idx1 < mid) || (idx2 < last)) {
                if ((idx2 == last) || ((idx1 < mid) && (nums[indices[idx1]] <= nums[indices[idx2]]))) {
                    tmp.push_back(indices[idx1]);
                    results[indices[idx1]] += semicount;
                    ++idx1;
                } else {
                    tmp.push_back(indices[idx2]);
                    ++semicount;
                    ++idx2;
                }
            }
            move(tmp.begin(), tmp.end(), indices.begin()+first);
        }
    }
};

//The improved one using the mergesort algorithm
vector<int> Solution::countSmaller (vector<int> & nums) {
    int n = nums.size();
    vector<int> results(n, 0);
    vector<int> indices(n, 0);
    iota(indices.begin(), indices.end(), 0);
    merge_countSmaller(indices, 0, n, results, nums);
    return results;
}

In my mind, this merge sort algorithm is tricky. And it cost my a lot of time to understand it. The array indices is used to stored the sorted indeices of the previous array. And since we use the merge sort algorithm, we sort the small partition first and then we merge them into a bigger partition and repeat the sort. And we can get that thought the partition is sorted, the elements in that partition still has the same elements. We sort the partitions just to make sure that every element that bigger than the current element have the count of the smaller elements in another partition is at least as much as the current one’s. Keep adding the count with other partitions and at last we will get the result we want.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值