C++半月刊

【C++半月刊#1】C++实用技巧——离散化

2019-02-09  本文已影响0人  小垚说球
离散化是程序设计中一个常用的技巧,它可以有效的降低时间和空间复杂度。

离散化,就是把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。
打个比方:现在有一组很大的数据

1,23424,21472313246768,6594,95,0,65535313

如果将这些数作为数组的下标来保存对应的属性时,我们将需要开一个很大的数组。以上方数据为例,这个数组至少要开21472313246768这么大的空间,这样很多题目的空间限制这关都过不了了,怎么办呢?当数据只需表示出它们之间的相对大小关系,而不需表示出具体数值时,我们就要用一个小技巧——离散化。
还是以上面的数据为例,经过离散化处理后,数据就成了:

1,4,6,3,2,0,5

神不神奇,意不意外!!!

——不意外!!!

在这里,我就献上处理数据的程序,教大家如何实现。
第一种方法:

const int N=1e5+7;
int t[N],a[N];
int main()
{
  cin>>n;
  for(int i=1;i<=n;i++)
    cin>>a[i],t[i]=a[i];
  sort(t+1,t+n+1);
  m=unique(t+1,t+n+1)-t-1;
  for(int i=1;i<=n;i++)
    a[i]=lower_bound(t+1,t+m+1,a[i])-t;
}

在这段代码中,a[]经过离散,范围就变成了m。解释一下,unique是c++自带的一个函数,表示对一个数列去重,然后返回不重复的元素个数,当然在后面要减去首地址。那么这种离散化对于有重复元素的数列也可以适用,但复杂度相对后面要讲的第二种方法会高些。
比如,这组数据:

1,23424,242,65466,242,0

进入这段代码后,首先会排个序得到:

0,1,242,242,23424,65466

然后会去重,得到:

0,1,242,23424,65466

然后离散化的到:

1,3,2,4,2,0

第二种方法:

const int N=1e5+7;
struct Node
{
  int v,id;
  bool operator < (const Node a)const
  {return v<a.v;}
}a[N];
int n,rank[N];
int main()
{
  cin>>n;
  for(int i=1;i<=n;i++)
  {
    cin>>a[i].v;
    a[i].id=i;
  }
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)
      rank[a[i].id]=i;
 }

这种方法复杂度比上面那一种要优,但不能处理重复元素。它直接用结构体存储原本的数列的元素的位置,然后排序以后将他们再重新赋值。那么rank[]就是结构体a[]离散化后的结果。

v: 3 6 5 10 8
id : 1 2 3 4 5

排序以后:

v: 3 5 6 8 10
id: 1 3 2 5 4

所以离散化以后:

v: 3 5 6 8 10
id: 1 3 2 5 4
rk: 1 2 3 4 5

在按原来的顺序排列:

v: 3 6 5 10 8
rk: 1 3 2 5 4

今天的讲解就到了这里,相信大家对离散化有一定的了解了。来,做个题目练练手吧:
P1056图形面积-vijos
P1667 数列-洛谷

来自简书
发表于:2019-2-9
已同步至:

参考文献:
离散化_百度百科
离散化 - HolseLee - 博客园

C Studio工作室出品

作者微博

上一篇 下一篇

猜你喜欢

热点阅读