目录
数组离散化应用场景:数组的值过大,不能用作数组的索引或者可用作数组索引但是会导致空间复杂度过大,而要解决的问题中只需要考虑元素之间的相对大小,不必考虑数组之间的绝对大小,比如求逆序对问题。数组离散化使用C++可很简单的实现,STL中有sort和unique,还有二分查找lower_bound。Java也有这些函数。本文使用jdk8的新特性—stream来实现数组离散化。
二分查找简介
二分查找应用场景:容器(数组或者集合)中的元素有序,且要根据value查找index。二分查找使用的是分治思想,不断将查找范围一分为二,直到找到给定的value或者找不到value返回。Java中的工具类Arrays和Collections中都有binarySearch函数,前者用于数组中的二分,后者用于集合的二分。在这里我是自己实现的二分查找,采用尾递归的形式进行二分查找,当然也可以用循环。代码如下:
public static int binarySearch(Integer[]arr,int s,int e,int val){
if(s>e)
return -1;
int ans=-1;
int mid=(s+e)/2;
if(arr[mid]==val)
return mid;
if(arr[mid]<val)
return binarySearch(arr,mid+1,e,val);
return binarySearch(arr,s,mid-1,val);
}
stream简介
jdk8的新特性stream,是一个非常强大好用的工具。像Array,Collection,Map这些都是Java的数据结构,是早就有了的,对应的Arrays,Collections中为这些数据结构提供相应的算法,但是并不是很快捷方便。而stream就是为这些数据结构提供了更强大的函数式编程的算法。要对容器排序,直接使用.sorted(),参数可以传一个lambda表达式,要对容器去重,直接.distinct(),最后要转换成数组的话,.toArray(Integer[]::new),注意里面的参数,是lambda函数的构造器引用,也是jdk8的新特性,还有成员方法引用,类静态方法引用等,再次不做详细扩展。
数组离散化的实现
思路:通过stream对传进来的数组排序、去重并通过终止操作toArray()转换成Integer[]数组,再遍历原数组中的每一个元素,查找该元素值在得到的Integer[]数组中的index,然后修改原数组中该指为index+1(这个随便,用index也没毛病,但是index+1就保证了从1开始,比如原数组:6 5 2 1 9,离散化后:4 3 2 1 5,和相对大小顺序是一样的),然后返回修改后的数组即可。代码如下:
public static int[] discrete(int[]copy){
Integer[] integers = Arrays.stream(copy).boxed().parallel().sorted().distinct().toArray(Integer[]::new);
for(int i=0;i<copy.length;++i){
int index=binarySearch(integers,0,integers.length,copy[i]);
copy[i]=index+1;
}
return copy;
}
完整代码
public class ArrayDiscrete {
public static int binarySearch(Integer[]arr,int s,int e,int val){
if(s>e)
return -1;
int ans=-1;
int mid=(s+e)/2;
if(arr[mid]==val)
return mid;
if(arr[mid]<val)
return binarySearch(arr,mid+1,e,val);
return binarySearch(arr,s,mid-1,val);
}
public static int[] discrete(int[]copy){
Integer[] integers = Arrays.stream(copy).boxed().parallel().sorted().distinct().toArray(Integer[]::new);
for(int i=0;i<copy.length;++i){
int index=binarySearch(integers,0,integers.length,copy[i]);
copy[i]=index+1;
}
return copy;
}
public static void main(String[] args) {
int[]arr=new int[]{6,5,3,6,9,1};
int[] ans=discrete(arr);
System.out.println(Arrays.toString(ans));
}
}