在ACM竞赛中可能经常需要对数据进行离散化处理, 通过改变他们的大小,但不改变他们的大小关系,这种做法往往可以节省空间,减低时空复杂度.
为实现数据的离散化, 首先需要对数组进行排序, 如果数据可能出现重复, 则需要对数据进行去重处理, 需要用到unique()函数, 下面是数据离散化的java实现.
/*
* Copyright (c) 2019 Ng Kimbing, HNU, All rights reserved. May not be used, modified, or copied without permission.
* @Author: Ng Kimbing, HNU.
* @LastModified:2019-04-11 T 13:06:26.985 +08:00
*/
package MyUtil;
import java.util.Arrays;
import java.util.Comparator;
public class Discretization {
/**
* Remove consecutive values from a sequence
*
* @param a the array
* @param first first index.
* @param last last index.
* @return The index designating the end of the resulting sequence.
*/
public static int unique(int[] a, int first, int last) {
if (first == last)
return last;
int result = first;
while (++first != last) {
if (!(a[result] == a[first])) {
a[++result] = a[first];
}
}
return ++result;
}
public static int unique(Object[] a, int first, int last, Comparator<Object> c) {
if (first == last)
return last;
int result = first;
while (++first != last) {
if (c.compare(a[result], a[first]) != 0) {
a[++result] = a[first];
}
}
return ++result;
}
/**
* Finds the first position in which @key could be inserted without changing the ordering.
*
* @param array the array
* @param size the size of the array.
* @param key The search item
* @return returns the index pointing to the first element <em>not less than</em> {@code key},
* or {@code size} if every element is less than {@code key}.
*/
public static int lowerBound(int[] array, int size, int key) {
int first = 0, middle;
int half, len;
len = size;
//binary search
while (len > 0) {
half = len >> 1;
middle = first + half;
if (array[middle] < key) {
first = middle + 1;
len = len - half - 1; //search in the right sub-sequence
} else
len = half; //search in the left sub-sequence, middle included.
}
return first;
}
public static int lowerBound(Object[] array, int size, Object key, Comparator<Object> c) {
int first = 0, middle;
int half, len;
len = size;
//binary search
while (len > 0) {
half = len >> 1;
middle = first + half;
if (c.compare(array[middle], key) < 0) {
first = middle + 1;
len = len - half - 1; //search in the right sub-sequence
} else
len = half; //search in the left sub-sequence, middle included.
}
return first;
}
static int upperBound(int[] array, int size, int key) {
int first = 0, len = size - 1;
int half, middle;
while (len > 0) {
half = len >> 1;
middle = first + half;
if (array[middle] > key)
len = half;
else {
first = middle + 1;
len = len - half - 1;
}
}
return first;
}
/**
* Discretize the array.
*
* @param a the array.
*/
public static void discretize(int[] a) {
Arrays.sort(a);
int newLen = unique(a, 0, a.length);
for (int i = 0; i < newLen; ++i)
a[i] = lowerBound(a, newLen, a[i]);
}
public static void discretize(int[] a, int length) {
Arrays.sort(a, 0, length);
int newLen = unique(a, 0, length);
for (int i = 0; i < newLen; ++i)
a[i] = lowerBound(a, newLen, a[i]);
}
public static int[] discretizeWithoutChanges(int[] a) {
int b[] = new int[a.length];
System.arraycopy(a, 0, b, 0, a.length);
Arrays.sort(b);
int newLen = unique(b, 0, b.length);
int[] ans = new int[newLen];
for (int i = 0; i < newLen; ++i)
ans[i] = lowerBound(b, newLen, b[i]);
return ans;
}
public static void main(String[] args) {
int[] a = {2, 0, 1, 9, 4, 1, 1};
discretize(a);
System.out.println(Arrays.toString(a));
int[] b = {2, 0, 1, 9, 4, 1, 1};
System.out.println(Arrays.toString(discretizeWithoutChanges(b)));
}
}