package com.interview.algorithms.array; import com.interview.basics.sort.RadixSorter; import com.interview.utils.ArrayUtil; /** * Created with IntelliJ IDEA. * User: stefanie * Date: 9/11/14 * Time: 6:05 PM * Given an int array, write code to remove duplicate numbers. Time O(N), Space O(1) * * Remove duplicate can be simplify with sort, so need a O(N) sort: Counter/Radix/Bucket. * Counter/Bucket need large space, so use Radix sort. * Refer: http://blog.csdn.net/hawksoft/article/details/6867493 * * Radix Sort could also use O(10) space for numbers [0-9], Refer to RadixSorter */ public class C4_55_DuplicateRemover { public static Integer[] remove(Integer[] numbers){ sort(numbers); int i = 0; int j = 1; while(j < numbers.length){ if(numbers[i] != numbers[j]){ numbers[++i] = numbers[j]; } j++; } while(++i < numbers.length) numbers[i] = 0; return numbers; } private static void sort(Integer[] numbers){ RadixSorter<Integer> sorter = new RadixSorter<>(); sorter.sort(numbers); } //radix sort code private static void sortInPlace(Integer[] numbers) { int theN = numbers.length; //从高位到低位开始排序,这里从31位开始,32位是符号位不考虑,或者单独考虑。 for (int i = 31; i >= 1; i--) { //当前排序之前的值,只有该值相同才进行快排分组,如果不相同,则重新开始另外一次快排 //这很关键,否则快排的不稳定就会影响最后结果. int thePrvCB = numbers[0] >> (i); //快排开始位置,会变化 int theS = 0; //快排插入点 int theI = theS - 1; //2进制基数,用于测试某一位是否为0 int theBase = 1 << (i - 1); //位基元始终为0, int theAxBit = 0; //分段快排,但总体上时间复杂度与快排分组一样. for (int j = 0; j < theN; j++) { //获取当前数组值的前面已拍过序的位数值。 int theTmpPrvCB = numbers[j] >> (i); //如果前面已排过的位不相同,则重新开始一次快排. if (theTmpPrvCB != thePrvCB) { theS = j; theI = theS - 1; theAxBit = 0; thePrvCB = theTmpPrvCB; j--;//重新开始排,回朔一位. continue; } //如果前面的数相同,则寻找第1个1,thI指向其 //如果相同,则按快排处理 int theAJ = (numbers[j] & (theBase)) > 0 ? 1 : 0; ;//(A[j] & (theBase)) > 0 ? 1 : 0;(A[j] >> (i - 1)) & 1 //如果是重新开始排,则寻找第1个1,并人theI指向其.这可以减少交换,加快速度. if (theI < theS) { if (theAJ == 0) { continue; } theI = j;//Continue保证J从theI+1开始. continue; } //交换. if (theAJ <= theAxBit) { ArrayUtil.swap(numbers, j, theI); theI++; } } } } }