离散化:当数据只与它们之间的相对大小有关,而与具体是多少无关时,可以进行离散化。
有些数据本身很大, 自身无法作为数组的下标保存对应的属性。
如果这时只是需要这堆数据的相对属性, 那么可以对其进行离散化处理。
比如:
9 1 0 5 4 与 5 2 1 4 3 的逆序对个数相同。
设有4个数:
1234567、123456789、12345678、123456
排序:123456<1234567<12345678<123456789
=> 1 < 2 < 3 < 4
那么这4个数可以表示成:2、4、3、1
这就很清晰了。。hh
过程:先排序——>"删除"相同的元素——>索引元素离散后的值
利用了 unique 和 lower_bound
unique的作用是“去掉”容器中相邻元素的重复元素(不一定要求数组有序),它会把重复的元素添加到容器末尾(所以数组大小并没有改变),而返回值是去重之后的尾地址.
由于返回的是容器末尾,所以如果想得到去重后的size,需要减去初始地址
用法:
size = unique(a,a + n)-b; size为容器大小
lower_bound()
函数lower_bound()在first和last中的前闭后开(“[ )”)区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置。
例子:(来自:https://blog.youkuaiyun.com/qq_40774175/article/details/80343164)
一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标
则
pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。
pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。
pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。
所以,要记住:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!~
返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置
3. upper_bound()
upper_bound返回的是最后一个大于val的位置,也是有一个新元素val进来时的插入位置。
又重新复习了一遍 lower_bound upper_bound (っ•̀ω•́)っ✎⁾⁾ 我爱学习
///离散化,跟数据本身的值没有什么关系,看相对大小
#include <bits/stdc++.h>
using namespace std;
const int maxx=5e5+10;
int n,a[maxx],b[maxx];
void print()
{
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}cout<<endl;
}
int main()
{
memset(b,0,sizeof(b));
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
for(int i=0;i<n;i++) cout<<a[i]<<" ";
cout<<endl;
int size=unique(a,a+n)-a;//size为离散化后的元素个数
//"去掉"容器中相邻元素的重复元素之后的size
// 并没有去掉,只是把相同的数字放到最后
cout<<size<<endl;
cout<<"unique去重以后(相同的放后面查找无影响): ";
for(int i=0;i<n;i++) cout<<a[i]<<" ";
cout<<endl;
cout<<"离散化之后的数组:";
for(int i=0;i<n;i++)
{
b[i]=lower_bound(a,a+size+1,a[i])-a+1;//因为是第几个位置所以加1
cout<<b[i]<<" ";
} cout<<endl;
cout<<"原数组:";
print();
return 0;
}