离散化
离散化:
概念:把一些很离散的点个重新分配,使它们尽量集中.
如在1e10的范围中取1e4个数据,如果不进行离散化,则要开辟1e10的空间,而实际上只要1e4的空间就可以
装下每次取出的数据,所以可通过离散化来集中这些数据.
离散化的本质就是建立一个映射关系,即第n大的数字对应是几,如一组数6,2,4,666,48,则我们只要建立出
映射关系:6--3 2--1 4--2 666--5 48--4即是进行离散化
法一: 用一个辅助的数组把所有要离散的数据存下来,然后进行排序(为了之后的二分).再进行去重,因为
要保证相同的元素在离散化后数字相同,再用二分把离散化后的数字放回原数组
代码实现:
int cast[maxn],arr[maxn],cnt,n; for (int i=1;i<=n;i++) { scanf("%d",&arr[i]); cast[i]=arr[i]; } sort(cast+1,cast+n+1); cnt=unique(cast+1,cast+n+1)-(cast+1); for (int i=1;i<=cnt;i++) { arr[i]=lower_bound(cast+1,cast+cnt+1,arr[i])-cast; }
以上得到的代码cast为所存的原数组的值,而arr存的是对应的大小下标值
法二:用一个结构来储存这个值的下标,这样就不用另外存一个数字,来储存两次这批数
代码实现:
struct node{int val;int id;}ns[MAX_N]; int cast[MAX_N]; for (int i=1;i<=n;i++) { scanf("%d",ns[i].val); ns[i].id=i; } sort(ns+1,ns+n+1); for (int i=1;i<=n;i++) { cast[ns[i].id]=i; }
此处cast存的是大小下标值,ns[i].id存的是原下标的值
法三:用map数据结构来实现离散化:
分析:定义一个map型结构mp,其中mp[i]=j;i表示这个数字是多少,j表示这个数所在的大小位置
代码实现:
map<int,int> mp; int n,c[maxn],st[maxn]; for (int i=1;i<=n;i++) { scanf("%d",&c[i]); st[i]=c[i]; } sort(st+1,st+n+1); for (int i=1;i<=n;i++) mp[st[i]]=i;
所以对于一个无序数组c,我们找c中任意一个数都可以快速知道它是第几大的数,且mp.size()的值就是
数组c的不重复的元素个数
法一的代码完整模板:
#include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <string> #include <vector> #include <queue> #include <map> #include <set> #include <algorithm> #define rep(i,s,n) for (int i = s; i <= n; ++i) #define fi first #define se second typedef long long ll; const int MAXN = ??; using namespace std; int arr[MAXN]; int cast[MAXN]; int n,new_n; void discretization() { sort(cast + 1, cast + 1 + n); new_n = unique(cast + 1, cast + 1 + n) - cast - 1; rep(i,1,n) arr[i] = lower_bound(cast + 1, cast + 1 + new_n, arr[i]) - cast; } int main() { scanf("%d",&n); rep(i,1,n) { scanf("%d",&arr[i]); cast[i] = arr[i]; } discretization(); rep(i,1,n) printf("%d ",arr[i]); return 0; }
法二的代码完整模板:
#include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <string> #include <vector> #include <queue> #include <map> #include <set> #include <algorithm> #define rep(i,s,n) for (int i = s; i <= n; ++i) #define fi first #define se second typedef long long ll; const int MAXN = ??; using namespace std; struct node { int val; int id; }ns[MAXN]; bool com(const node& n1, const node& n2) { return n1.val < n2.val; } int cast[MAXN]; int n; void discretization() { sort(ns + 1, ns + 1 + n, com); rep(i,1,n) cast[ns[i].id] = i; } int main() { scanf("%d",&n); rep(i,1,n) { scanf("%d",&ns[i].val); ns[i].id = i; } discretization(); rep(i,1,n) printf("%d ",cast[i]); }
法三的代码模板:
#include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <string> #include <vector> #include <queue> #include <map> #include <set> #include <algorithm> #define rep(i,s,n) for (int i = s; i <= n; ++i) #define fi first #define se second using namespace std; typedef long long ll; typedef pair<int,int> pii; const int MAXN = 10; map<int,int> m; int n,new_n; int arr[MAXN]; int cast[MAXN]; void discretization() { sort(cast + 1, cast + 1 + n); new_n = unique(cast + 1, cast + 1 + n) - cast - 1; rep(i,1,new_n) m[cast[i]] = i; } int main() { scanf("%d",&n); rep(i,1,n) { scanf("%d",&cast[i]); arr[i] = cast[i]; } discretization(); rep(i,1,n) printf("%d %d\n",arr[i],m[arr[i]]); }
法三的一道实例题:
给定一个长度为N的数组,数组的N个元素已知,并从中取出K(K<=N)个数,请你寻找一个最优选法,使得这K
个数中互不相同的数达到最大,求这个最大值.
本题的数字的范围达到了1e10,但数组长度只达到了1e5,所以要离散化,使得原本1e10的空间集中到1e5,
本题便可通过map数据结构来进行实现(利用map有预留空间但不占能力,即你有存在这个值,这个空间才
会开起来,否则就不会开这个空间)
代码实现:
#include <bits/stdc++.h> using namespace std; const int MAX_N=300005; int N,K; int c[MAX_N]; map<int,int> mp; int main() { scanf("%d%d",&N,&K); for (int i=1;i<=N;i++) scanf("%d",c[i]); for (int i=1;i<=K;i++) mp[c[i]]++; int ans=mp.size(); for (int i=K+1;i<=N;i++) { mp[c[i]]++; mp[c[i-K]]--; if (mp[c[i-K]]==0) mp.erase(c[i-K]); ans=max(ans,(int)mp.size());//mp.size()即为不同数的个数 } printf("%d",ans); }