离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。
概述
离散化本质上可以看成是一种哈希,是程序设计中一个常用的技巧,它可以有效的降低时间复杂度。其基本思想就是在众多可能的情况中,只考虑需要用的值。离散化可以改进一个低效的算法,甚至实现根本不可能实现的算法。
通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。例如:
原数据:1,999,100000,15;处理后:1,3,4,2;
原数据:{100,200},{20,50000},{1,400};
处理后:{3,4},{2,6},{1,5};
实现
C++ 离散化有现成的 STL 算法:
// 思路:先排序,再删除重复元素,最后就是索引元素离散化后对应的值
// a[i] 为初始数组,下标范围为 [1, n]
// len 为离散化后数组的有效长度
std::sort(a + 1, a + 1 + n);
len = std::unique(a + 1, a + n + 1) - a - 1;
// 离散化整个数组的同时求出离散化后本质不同数的个数。
// 在完成上述离散化之后可以使用 std::lower_bound 函数查找离散化之后的排名(即新编号):
std::lower_bound(a + 1, a + len + 1, x) - a; // 查询 x 离散化后对应的编号
Java 自实现版本
import java.util.Arrays;
import java.util.SortedSet;
import java.util.TreeSet;
public class Discretization {
public static int lowerBound(int[] arr,int target){ //找到第一个大于等于x的数的位置
int l=0;
int r=arr.length;
while (l<r){
int mid=l+(r-l)/2;
if(arr[mid]>=target){
r=mid;
}else{
l=mid+1;
}
}
return l==arr.length?-1:l;
}
public static int[] solve(int[] array){
SortedSet<Integer> set=new TreeSet<Integer>();
//利用TreeSet可以同时实现排序和去重 可以代替c++中的unique实现
for(int i=0;i<array.length;++i){
set.add(array[i]);
}
int[] b=new int[set.size()]; //将去重排序的数组赋值给b数组
int ct=0;
for(int cur:set){
b[ct++]=cur;
}
for(int i=0;i<array.length;++i){
array[i]=lowerBound(b,array[i])+1; //利用lowerBound找到该数值的排位(rank)
//排名代表大小 越前越小 越后越大
}
//10000000,2,2,123123213离散化成2,1,1,3
return array;
}
public static void main(String[] args) {
int[] a={10000000,2,2,123123213};
System.out.println(Arrays.toString(solve(a)));
}
}
实战
题解
使用了树状数组+离散化
import java.util.HashMap;
import java.util.SortedSet;
import java.util.TreeSet;
class Solution {
int[] t = new int[50002];
public int lowBit(int x) {
return x & -x;
}
public int query(int i) {
int ans = 0;
for (--i; i > 0; i -= lowBit(i) ) {
ans += t[i];
}
return ans;
}
public void update(int i, int x) {
for (; i < t.length; i += lowBit(i)) {
t[i] += x;
}
}
public int reversePairs(int[] nums) {
SortedSet<Integer> set = new TreeSet<>();
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
set.add(nums[i]);
}
int i = set.size() + 1;
for(int x : set) {
map.put(x, i);
i--;
}
int ans = 0;
for (i = 0; i < nums.length; i++) {
int hi = map.get(nums[i]);
ans += query(hi);
update(hi, 1);
}
return ans;
}
}