Problem can be solved if array is dived into sub ranges and then sort these sub ranges. Let's see in details,
Given array = [10, 12, 8, 17, 3, 24, 19]
Now divide array in sub range of length 4 and sort these sub ranges as showed below,
Sub rang sorted array
.................... ...............
| 8 | 10 | 12 | 17 | | 3 | 19 | 24 |
.................... ...............
2 0 1 3 4 6 5 => index
Let's take first entry of sub range sorted array which is 8 and try to find number of right elements greater then of 8
As you see in above number 8 belong to first sub range and because sub ranges are sorted, elements in sub range are in ascending order but not in there index order. It means in current sub range, we have to compare index of all elements at right of element 8 with index of element 8
Index of 8 is 2 but 10 have index = 0, it means 10 is at left of 8 in input array,
Index of 12 is also less then index of 8, it means 12 is at left of 8 in input array,
Index of 17 is 3 which is greater than index of 8, it means 17 is at the right of 8 in input array and can be considered greater element,
After comparing index of 8 with index of all right elements of current sub range, right greater element count = 1, let's look at the next range,
After sub range of 8, things got totally changed, now we know this sub range is at the right of the sub range element 8 belongs, it means we don't have to compare index of 8 with elements or this range, all are at right of element 8 and we only have to find how many are greater than 8,
Now we compare first element of right sub range with 8 and as you can see above first element is 3 which is less then 8 but in case if first element of right sub range is greater then current element then we can increment count directly to number of elements present in right sub range.
Because first element 3 is less then 8 we find upper bound of 8 in right sub range and that is 19 and all the elements from 19 in right sub range are greater than 8, so there are two elements 19, 24 and due to this count incremented by two and become count = 3
Finally there are 3 right elements greater than element 8.
In similar way number of greater right elements can be found for all elements and result array would be,
x(A) = [4, 3, 3, 2, 2, 0, 0]
Conclusion is, by dividing input array in sorted sub range, greater elements at right can be found by following steps,
- Compare index of all right elements of current sub range,
- Compare first element of right sub range and if,
i. first element is greater then current element than all element of right range are greater then current element,
ii. first element is less than, then find upper bound of current element in right sub range, and elements from upper bound in right sub range are greater than current element.
- Repeat step 2 for all right sub ranges.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using std::cout;
std::vector<std::pair<int, std::size_t>> arrayOfSortedSubRange(std::size_t subRangeSize,
const std::vector<int>& numArr){
std::vector<std::pair<int, std::size_t>> res;
res.reserve(numArr.size());
for(std::size_t i = 0, numArrSize = numArr.size(); i < numArrSize; ++i){
res.emplace_back(numArr[i], i);
}
for(std::vector<std::pair<int, std::size_t>>::iterator it = res.begin(), endIt = res.end(); endIt != it;){
std::vector<std::pair<int, std::size_t>>::iterator rangeEndIt = it + std::min<std::ptrdiff_t>(endIt - it,
subRangeSize);
std::sort(it, rangeEndIt, [](const std::pair<int, std::size_t>& a, const std::pair<int, std::size_t>& b){
return a.first < b.first;});
it = rangeEndIt;
}
return res;
}
std::size_t rightGreterElmentCountOfNumber(int num, std::vector<std::pair<int, std::size_t>>::const_iterator rightSubRangeIt,
std::vector<std::pair<int, std::size_t>>::const_iterator endIt){
std::size_t count = 0;
std::vector<std::pair<int, std::size_t>>::const_iterator subRangEndIt = rightSubRangeIt +
std::min<std::ptrdiff_t>(endIt - rightSubRangeIt, 4);
while(endIt != rightSubRangeIt){
if(rightSubRangeIt->first > num){
count += subRangEndIt - rightSubRangeIt;
}
else{
count += subRangEndIt -
std::upper_bound(rightSubRangeIt, subRangEndIt, num, [](int num,
const std::pair<int, std::size_t>& element){ return num < element.first;});
}
rightSubRangeIt = subRangEndIt;
subRangEndIt += std::min<std::ptrdiff_t>(endIt - subRangEndIt, 4);
}
return count;
}
std::vector<std::size_t> rightGreaterElementCountForLessThanFiveNumbers(const std::vector<int>& numArr){
std::vector<std::size_t> res(numArr.size(), 0);
std::vector<std::size_t>::iterator resIt = res.begin();
for(std::vector<int>::const_iterator it = numArr.cbegin(), lastIt = it + (numArr.size() - 1); lastIt != it;
++it, ++resIt){
*resIt = std::count_if(it + 1, numArr.cend(), [num = *it](int rightNum){return rightNum > num;});
}
return res;
}
std::vector<std::size_t> rightGreaterElementCount(const std::vector<int>& numArr){
if(numArr.size() < 5){
return rightGreaterElementCountForLessThanFiveNumbers(numArr);
}
std::vector<std::size_t> resArr(numArr.size(), 0);
std::vector<std::pair<int, std::size_t>> subRangeSortedArr = arrayOfSortedSubRange(4, numArr);
for(std::vector<std::pair<int, std::size_t>>::const_iterator it = subRangeSortedArr.cbegin(),
endIt = subRangeSortedArr.cend(); endIt != it;){
std::vector<std::pair<int, std::size_t>>::const_iterator rightNextSubRangeIt = it + std::min<std::ptrdiff_t>(
endIt - it, 4);
for(std::vector<std::pair<int, std::size_t>>::const_iterator eleIt = it; rightNextSubRangeIt != eleIt; ++eleIt){
std::size_t count = std::count_if(eleIt, rightNextSubRangeIt, [index = eleIt->second](
const std::pair<int, std::size_t>& element){ return index < element.second;});
if(endIt != rightNextSubRangeIt){
count += rightGreterElmentCountOfNumber(eleIt->first, rightNextSubRangeIt, endIt);
}
resArr[eleIt->second] = count;
}
it += std::min<std::ptrdiff_t>(endIt - it, 4);
}
return resArr;
}
int main(){
std::vector<std::size_t> res = rightGreaterElementCount({10, 12, 8, 17, 3, 24, 19});
cout<< "[10, 12, 8, 17, 3, 24, 19] => [";
std::copy(res.cbegin(), res.cbegin() + (res.size() - 1), std::ostream_iterator<std::size_t>(cout, ", "));
cout<< res.back()<< "]\n";
}
Output:
[10, 12, 8, 17, 3, 24, 19] => [4, 3, 3, 2, 2, 0, 0]