离散化:
不改变数据相对大小的情况下,对数据进行相应的缩小。
学术化一点: 把无限空间中有限的个体(有很多重复元素)映射到有限的空间中去,以此提高算法的时空效率。
例如 4 3 9 1000000 1000000000
可以映射成 2 1 3 4 5
利用STL离散化
思路是:先排序,再删除重复元素,最后索引元素离散化对应的值。
假定待离散化的的序列为a[n],b[n]是a[n]的一次遍历,对应以上三步
sort(b+1,b+1+n);
int len=unique(b+1,b+1+n)-b-1;//len是离散化之后元素的个数(删除重复元素)
for(i=1 ; i<=n ; i++ ) a[i]=lower_bound(b+1 , b+len+1 , a[i] ) - b ;//a[i]为离散化之后对应的数组
unique函数 (详解 添加链接描述)
unique(数组首元素地址,数组末地址) - 数组首元素地址
/**/
#include<stdio.h>
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
ll a[1000010],b[1000010],sum[1000010];
int main()
{
int i,len,n;
int a[20];
while(~scanf("%d",&n))
{
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
printf("%d\n",n);
for(i=1;i<=n;i++)
{
printf("%d ",a[i]);
}
printf("\n");
sort(a+1,a+1+n);
int len=unique(a+1,a+1+n)-a-1;
printf("%d\n",len);
for(i=1;i<=len;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
return 0;
}
输出
10
4 4 5 9 2 5 8 1 1 9//原始a[i]
6
1 2 4 5 8 9//unique后的a[i]
lower_bound函数(详解添加链接描述)
lower_bound( begin,end,num)-num:从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
代码:
#include<bits/stdc++.h>
using namespace std;
#define N 10000
int a[N],b[N];
int main()
{
int i,n;
scanf("%d",&n);
for(i=1; i<=n; i++)
{
scanf("%d",&a[i]);
b[i]=a[i];//去重后会改变a数组元素,所以一开始先让b存一遍a
}
printf("%d\n",n);
for(i=1;i<=n;i++)
printf("%d ",a[i]);
printf("\n");
sort(a+1,a+n+1);//排序后才能去重
int len=unique(a+1,a+n+1)-a-1;//unique去重,使a[i]大小与下标i对应,并得到去重后的长度
printf("%d\n",len);
for(i=1;i<=len;i++)
printf("%d ",a[i]);
printf("\n");
for(i=1; i<=n; i++)
b[i]=lower_bound(a+1,a+1+len,b[i])-a;//把b[i]放在去重排序后的a序列里面去比,找到最后一个不比b[i]小的元素并返回该元素下标i,所以数组b对应未去重时的序列的元素是第几小
printf("%d\n",n);
for(i=1; i<=n; i++)printf("%d ",b[i]);
}
输入
10
5 6 8 4 5 8 4 1 3 6
输出
10
5 6 8 4 5 8 4 1 3 6
6
1 3 4 5 6 8//unique后的a[i]
10
10 4 5 6 3 4 6 3 1 2 5//lower_bound后的b[i]