数据离散化
对应 1331. 数组序号转换
一、概述
数据离散化是一个非常重要的思想。
现在给出这样的一个问题,有1e5个数,每个数的范围在-1e18至1e18之间,有1e5次询问,每次有一个k,询问第k大的数字出现的次数。
当然,第一想法是用map解决,但是掐指一算复杂度,用map计数以后,对于每一次询问,都需要对map进行一遍遍历,显然复杂度过不去。
这时候我们注意到,对于这个问题,我们要关心的只是数据间的大小关系,而不是具体的数值,所以我们只需要将其一一映射即可。
我们来看一下定义:离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。
通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。例如:
对于一组数据3, 100001357, -256, 378, 4, 1,如果将这些数据处理成3, 6, 1, 5, 4, 2,这样的话,直接通过下标索引,就能找到我们要的答案。
样例输入
6
3 100001357 -256 378 4 1
样例输出
3 6 1 5 4 2
二、原理与操作
假如你只想简单操作一下,如求个逆序对什么的,那直接排序后将它的顺序覆盖回去就可以啦。(它不能去重)
假如你想写的更加专业就要采用以下步骤:
1、排序
2、去重
3、索引
首先我们要对所要进行离散化的数据进行排序:一般使用sort对数组或结构体排序。
然后是去重操作,为了写出高效的代码,我们需要复习两个STL函数:unique()和lower_bound(),他们同时隶属于#include<algorithm>。
unique的作用是“去掉”容器中相邻元素的重复元素(不一定要求数组有序),它会把重复的元素添加到容器末尾(所以数组大小并没有改变),而返回值是去重之后的尾地址;
函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置。【ps.upper_bound是返回第一个大于b[x]的指针,upper_bound()=lower_bound()+1】
代码如下:
class Solution {
public:
vector<int> arrayRankTransform(vector<int>& arr) {
vector<int> b = arr;
sort(b.begin(), b.end());
b.erase(unique(b.begin(), b.end()), b.end());
for(auto &x: arr)
x = upper_bound(b.begin(), b.end(), x) - b.begin();
return arr;
}
};
当然可以用map 来加速
class Solution:
def arrayRankTransform(self, arr: List[int]) -> List[int]:
data = sorted(set(arr))
mp = dict()
for i in range(len(data)):
mp[data[i]] = i+1
return [mp[i] for i in arr]