离散化基于这样一种思想:当想要存储的数据的量较小,而数值较大,并且操作对象是数值时,使用数值的排名来代表数值进行操作.
与哈希算法很相似,不过这种算法一定不会发生冲突,但是预处理复杂度为O(NlogN),单次查询的复杂度是O(logN).
给出的数在32位有符号整数范围内.
如果每当一个数字第一次出现时,将其记录为已出现,当下一次出现时就可以忽略它了.
为了进行这样的记录,使用排名代表数字,使得每个数字(重复视为同一个数字)与其排名形成一一对应关系.使用discrete函数构建这种关系:
// 假设给定的ind个数据已经复制到了dis数组中 void discrete() { // O(NlogN) sort(dis + 1, dis + 1 + ind); ind = unique(dis + 1, dis + 1 + ind) - dis - 1; // unique的复杂度是O(N) }
现在dis数组中就有了排序并去重后的数字,排名为i的数字为dis[i]的值.之后处理dis[i]时用i代替之.
例如,读取到一个数字123456789,使用query函数获取其排名:
// O(logN) int query(int x) { return lower_bound(dis + 1, dis + 1 + ind, x) - dis; }
假设query(123456789)返回了5,那么检查排名为5的数字是否已经出现过了(used[5] == true),如果没有出现过就输出dis[5]并标记为已出现,否则直接读取下一个数字.
#include <algorithm> #include <cstdio> #include <cstring> #include <iostream> using namespace std; #define SIZE 50000 int s[SIZE + 10], dis[SIZE + 10], idx; bool used[SIZE + 10]; inline int read() { char ch = getchar(); int x = 0, f = 1; while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } void discrete() { sort(dis + 1, dis + 1 + idx); idx = unique(dis + 1, dis + 1 + idx) - dis - 1; } int query(int x) { return lower_bound(dis + 1, dis + 1 + idx, x) - dis; } void solve() { int n = read(); idx = 0; memset(used, 0, sizeof(bool) * (n + 1)); for (int i = 1; i <= n; i++) { s[i] = read(); dis[++idx] = s[i]; } discrete(); for (int i = 1; i <= n; i++) { int ns = query(s[i]); if (!used[ns]) { printf("%d ", s[i]); used[ns] = true; } } puts(""); } int main() { int t; t = read(); while (t--) solve(); return 0; }