前言:
关于上周打的一场积分赛,b题为简单离散化之后dp就ok,但是比赛期间完全没想到离散化,导致TLE之后不会优化,就没写出来,赛后补完题,又去练了一些离散化的题,也算有了一点理解
离散化
所谓离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。
通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。
比如说题目需要对1,10,100,90000000,10101010101数据进行处理,如果不进行离散化处理那么就需要开大小为10101010101的数组保存操作结果,很明显无法实现,这时候就需要用到离散化处理数据。
代码实现
在网上的离散化处理代码一般都是排序,去重,索引的方法
const int N=2e5+5;
int n,a[N],t[N];
void solve()
{
// 读入数据
cin>>n;
for (int i=1;i =n;i++)
{
cin>>a[i];
t[i]=a[i]; //复制到 t中
}
//对数组 t排序
sort(t+1,t+1+n);
//去重并获取去重后的数组大小
int q=unique(t+1,t+1+n)-(t+1);
for (int i=1;i<=n; i++){
// 映射
a[i]=lower_bound(t+1,t+1+q,a[i])-t;
}
return ;
}
但我是利用map来实现离散化,个人感觉更加好用一点
const int N=2e5+5;
int n,a[N],sum[N];
void solve()
{
for(int i=1;i<=n;i++)
cin>>sum[N];
sort(sum+1,sum+1+n); //排序,某些题目可能不需要
map<int,int>mp;
int q=0;
//a[++q]=0; //把起点设为 0
for(int i=1;i<=n;i++)
{
if(!mp[a[i]]) //判重
{
a[++q]=a[i];
mp[a[i]]=q; //记录索引
}
}
//得到一个a数组,索引从1~q,用map查找索引
return ;
}
map查找的时间复杂度为O (log (n)),如果需要优化时间还可以使用unordered_map,unordered_map插入和查询速度接近于O (1) 。但是如果对内存使用特别严格,需要程序尽可能少消耗内存,那么应该是用map,因为unordered_map占用内存较多。
unordered_map已经加到C++11标准(编译时添加编译选项:--std=c++11)
#include<unordered_map>
using namespace std;
//unordered_map使用的头文件
const int N=2e5+5;
unordered_map<int,int>ump;
//unordered_map因为占用内存多,开在函数外
int n,a[N],sum[N];
void solve() //别的部分和 map一样
{
for(int i=1;i<=n;i++)
cin>>sum[N];
sort(sum+1,sum+1+n);
int q=0;
//a[++q]=0; //把起点设为 0
for(int i=1;i<=n;i++)
{
if(!ump[a[i]])
{
a[++q]=a[i];
ump[a[i]]=q;
}
}
return ;
}
总结
离散化是程序设计中一个常用的技巧,它可以有效的降低时间复杂度。其基本思想就是在众多可能的情况中,只考虑需要用的值。离散化可以改进一个低效的算法,甚至实现根本不可能实现的算法。要掌握这个思想,必须从大量的题目中理解此方法的特点。