离散化就是把有限数量但范围很大数据,如果不考虑数值大小,只关注相对顺序, 那么可以映射到一个小范围去
分为两种,保序离散化和无序离散化
无序离散化适用于只关注数据本身,而不关注它们顺序的离散化
保序离散化即保证离散化后的数据依旧符合原先顺序不变。
保序离散化需要另开一个数组(vector),来方便进行排序 + 判重 + 二分 = 离散化
当然不保序的也少用,一般都保序离散化
不保序
可以开一个map 或者 hash 表来映射
map <int, int> a;
unordered_map<int, int> a;
unordered_map<int, int> a;
int g[N];
int cnt = 0;
for (int i = 1; i <= n; i ++ )
{cin >> g[i];a[g[i]] = ++ cnt ; // a为离散化数组
}
保序
一般离散化的都是坐标之类的东西
新开数组 g,内容和原数组 a 相同,把 g 排序加去重(细节不在强调),然后用二分查找,返回下标即为离散化大小。
- 预处理(复制数组)
- 排序
- 去重
- 二分查找
代码
vector 版
const int N = 100010;int n, k;
int a[N]; // 原数组
vector<int> g; // 离散数组,存储离散化后的 数据int find(int x) // 给与一个原值(可能是下标),查询离散化后的值
{int l = 0, r = k - 1; // 因为 g 是 vector 从0开始储存while (l < r){int mid = l + r >> 1;if (x <= g[mid]) r = mid;else l = mid + 1;}return l + 1;
}int main()
{cin >> n;for (int i = 1; i <= n; i ++ ) {cin >> a[i];g.push_back(a[i]); }sort(g.begin(), g.end());g.erase(unique(g.begin(), g.end()), g.end()); //去重,unique本质是把相邻项// (即重复项)放到末尾,并在处理完之后返回一个指向去重后的末尾项的下一项的迭代器,// 而erase是删除元素,如此使用可以直接删除末尾的重复元素int k = g.size(); // k 为去重后数组长度// 后续调用 find() 即可找到离散化之后的的下标
}
数组版
const int N = 10010;int k, n;
int a[N]; // 原数组
int g[N];int find(int x)
{int l = 1, r = k;while (l < r){int mid = l + r >> 1;if (x <= g[mid]) r = mid;else l = mid + 1;}return l;
}int main()
{cin >> n;for (int i = 1; i <= n; i ++ ) {cin >> a[i];}memcpy(g, a, sizeof g); // 复制数组使用,意为把 a 复制给 g, sizeof g的长度// sizeof 给数组使用,可直接返回数组长度sort(g + 1, g + 1 + n); // 自行体会int k = unique(g + 1, g + 1 + n) - (g + 1); // unique 返回末地址的下一位,// 减去首地址就是去重后的长度// 后续调用 find() 即可找到离散化之后的的下标
}