离散化

离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。——摘自百度百科

离散化总体来说还是很有用的,下面先上一段核心代码

struct node
{
    int data,pos;
}p[100001];
bool cmp(node x,node y)
{
    return x.data < y.data;
}        
scanf("%d",&n);
    for(int i = 1;i <= n;i++) 
    {
        scanf("%d",&p[i].data);//输入数据值
        p[i].pos = i;//记录数据的位置
    }
    sort(p + 1,p + n + 1,cmp);//将数据按值从小到大排序
    for(int i = 1;i <= n;i++)
    {
        if(i == 1 || p[i].data != p[i - 1].data) now++;//如果当前值与上一个值不同,则新建立一个映射
        g[p[i].pos] = now;//g数组用来记录一个数据的映射值
        h[now] = p[i].data;//h数组用来记录被映射的元素的值
    }
    for(int i = 1;i <= n;i++) f[g[i]]++;    //f数组记录一个元素的出现次数

具体有什么作用呢?比如说,你要输入的数据一共有10^5个,但是输入数据的值有可能达到10^9甚至更大。如果我们要统计每一种数据出现了多少次,此时我们显然不可能开数组f[i]来记录数字i出现了多少次,因为会爆空间。此时我们发现,这些数据大部分不是连续的,而且中间有好多空间被浪费了。比如输入1,2,4,8,1000000.这样像10,11,100,1000……等等空间全部被浪费,所以我们要用离散化将这些值映射到一个新数组中,这样我们只需要开与输入数据数量等大的数组了。

这样,原来的元素1,2,4,8,1000000就会被映射成为1,2,3,4,5.同时,离散化还会保持数据的相对大小不变。

例题:

题目描述

LYK拥有n个数,这n个数分别是a1,a2,…,an。

有一天它做了一个梦,在梦里它的这n个数有部分被小偷偷走了,只剩下了m个数b1,b2,…,bm。它想知道有哪些数字被小偷偷走了!

LYK告诉你a和b的值,你需要从小到大的告诉LYK,哪些数字不见了!

输入格式(number.in)

    第一行一个数n,第二行n个数ai,表示一开始的数字。

    第三行一个数m,第四行m个数bi,表示剩下的数字。

输出格式(number.out)

    一行n-m个数,从小到大输出所有被偷走的数字。

这道题当然可以直接排序后O(n)扫一波,不过因为刚刚学完离散化,数据规模也到了10^9,所以使用离散化解题。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
    int data,pos;
}p[100001];
int b[100001],f[100001],g[100001],h[100001];
int now,n,m,k;
bool cmp(node x,node y)
{
    return x.data < y.data;
}
int main()
{
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    scanf("%d",&n);
    for(int i = 1;i <= n;i++) 
    {
        scanf("%d",&p[i].data);
        p[i].pos = i;
    }
    sort(p + 1,p + n + 1,cmp);
    for(int i = 1;i <= n;i++)
    {
        if(i == 1 || p[i].data != p[i - 1].data) now++;
        g[p[i].pos] = now;
        h[now] = p[i].data;
    }
    for(int i = 1;i <= n;i++) f[g[i]]++; 
    scanf("%d",&m);
    for(int i = 1;i <= m;i++)
    {
        scanf("%d",&b[i]);
    }
    sort(b + 1,b + m + 1);
    for(int i = 1;i <= m;i++)
    {
        while(h[k] != b[i]) k++;
        f[k]--;
    }
    for(int i = 1;i <= now;i++)
    {
        for(int j = 1;j <= f[i];j++)
        printf("%d ",h[i]);
    }
    return 0;
}

基本思想与上面相同。

当你意识到,每个上一秒都成为永恒。
原文地址:https://www.cnblogs.com/captain1/p/8424057.html