题目来源leetcode 315
给定一个乱序的数字序列A,生成一个序列B。B[i]表示A[i+1]到A的最后一项中比A[i]小的数字的个数。
如果用简单的扫描,需要O(n^2)的复杂度,我们寻求更好的办法。
设原序列为A,所求序列为B,所有元素初始化为0。构造一个结构体,保存了A中每个元素的值和下标,设置结构体序列C,对C进行按元素的值从大到小的归并排序。在归并两个已经
给定一个乱序的数字序列A,生成一个序列B。B[i]表示A[i+1]到A的最后一项中比A[i]小的数字的个数。
如果用简单的扫描,需要O(n^2)的复杂度,我们寻求更好的办法。
设原序列为A,所求序列为B,所有元素初始化为0。构造一个结构体,保存了A中每个元素的值和下标,设置结构体序列C,对C进行按元素的值从大到小的归并排序。在归并两个已经
排好序的序列X和Y的过程中,如果在比较X与Y两个头元素P、Q的值大小的过程中,出现了P>Q的情况,那么就说明P元素比Q元素及其在Y序列中后面的元素都要大。通过P元素封装的下标,可以找到其应该对应B序列中的哪个位置,这样就可以更新B序列。每一次归并的更新都不会重复计算或漏计,当归并排序完成之后,B序列就更新完毕了。复杂度和归并排序相同,为O(nlogn)。
struct num
{
int v;
int index;
num()
{
}
num(int x, int y)
{
v = x;
index = y;
}
};
void merge(vector<int>& ans, vector<num>& set, int left1, int right1, int left2, int right2)//稍作修改的归并过程
{
int i = left1, j = left2;
vector<num> temp;
while (1)
{
if (i > right1&&j > right2)
{
break;
}
if (i > right1)
{
temp.push_back(set[j]);
j++;
}
else
{
if (j > right2)
{
temp.push_back(set[i]);
i++;
}
else
{
if (set[i].v > set[j].v)
{
temp.push_back(set[i]);
ans[set[i].index]+=(right2-j+1);//更新最终的答案序列
i++;
}
else
{
temp.push_back(set[j]);
j++;
}
}
}
}
for (int i = left1; i <=right2; i++)
{
set[i] = temp[i-left1];
}
}
void mergesort(vector<int>& ans, vector<num>& set, int left, int right)
{
if (left == right)
return;
mergesort(ans, set, left, (left+right)/2);
mergesort(ans, set, (left + right) / 2+1, right);
merge(ans, set, left, (left + right) / 2, (left + right) / 2+1, right);
}
vector<int> countSmaller(vector<int>& nums) {
vector<num> set(nums.size());
vector<int> ans(nums.size(), 0);
if (nums.size() == 0)//讨论原序列为空的情况
return ans;
for (int i = 0; i < nums.size(); i++)
{
set[i].v = nums[i];
set[i].index = i;
}
mergesort(ans, set, 0, nums.size() - 1);
return ans;
}