1、小范围排序
已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。
给定一个int数组A,同时给定A的大小n和题意中的k,请返回排序后的数组。
[2,1,4,3,6,5,8,7,10,9],10,2
返回:[1,2,3,4,5,6,7,8,9,10]
代码如下:
public class ScaleSort {
public int[] sortElement(int[] A, int n, int k) {
if (A == null || n < k || A.length == 0) {
return A;
}
// 首次调整好为A[0]~A[k-1]范围的小根堆
int[] heap = firstHeap(A, k);
for (int i = k; i < n; i++) {
A[i-k] = heap[0];
heap[0] = A[i];
heapAdjust(heap, 0, k);
}
for(int j = n-k;j<n;j++){
A[j] = heap[0];
swap(heap,0,k-1);
heapAdjust(heap, 0, --k);
}
return A;
}
//循环插入A[0]~A[k-1]到heap
private int[] firstHeap(int[] A, int k) {
int[] heap = new int[k];
for (int i = 0; i < k; i ++) {
heapInsert(heap, A[i], i);
}
return heap;
}
//构建有序的heap数组
private void heapInsert(int[] heap, int value, int index) {
heap[index] = value;
while (index != 0) {
int parent = (index - 1) / 2;
if (heap[parent] > heap[index]) {
swap(heap, parent, index);
index = parent;
} else {
break;
}
}
}
private void swap(int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
/**
* 构建小根堆
*/
private void heapAdjust(int[] temp,int begin, int size) {
//左孩子
int left = begin * 2 + 1;
int right = begin * 2 + 2;
int smallest = begin;
while(left < size){
if(temp[left]<temp[smallest]){
smallest = left;
}
if(left + 1<size && temp[right]<temp[smallest]){
smallest = right;
}
if(smallest != begin){
swap(temp,begin,smallest);
}else{
break;
}
begin = smallest;
left = begin * 2 + 1;
right = begin * 2 + 2;
}
}
}
2、重复值判断
请设计一个高效算法,判断数组中是否有重复值。必须保证额外空间复杂度为O(1)。给定一个int数组A及它的大小n,请返回它是否有重复值。
public boolean checkDuplicate(int[] a, int n) {
for (int i = n / 2; i > 0; i--) {
heapAdjust(a, i - 1, n);
}
for (int j = n - 1; j > 0; j--) {
swap(a, 0, j);
heapAdjust(a, 0, j);
}
for (int k = 1; k < n; k++) {
if (a[k - 1] == a[k]) {
return true;
}
}
return false;
}
private void swap(int[] a, int index1, int index2) {
int temp = a[index1];
a[index1] = a[index2];
a[index2] = temp;
}
// 取左孩子
private int getLeftChild(int i) {
return 2 * i + 1;
}
// 调整为大根堆
private void heapAdjust(int[] a, int i, int n) {
int parent = a[i];
int leftChild = getLeftChild(i);
while (leftChild <= n - 1) {
if (leftChild < n - 1 && a[leftChild] < a[leftChild + 1]) {
leftChild++;
}
if (a[leftChild] <= parent) {
break;
}
a[(leftChild - 1) / 2] = a[leftChild];
leftChild = getLeftChild(leftChild);
}
a[(leftChild - 1) / 2] = parent;
}
}
有两个从小到大排序以后的数组A和B,其中A的末端有足够的缓冲空容纳B。请编写一个方法,将B合并入A并排序。给定两个有序int数组A和B,A中的缓冲空用0填充,同时给定A和B的真实大小intn和int m,请返回合并后的数组。
public int[] mergeAB(int[] A, int[] B, int n, int m) {
while(m!=0){
if(n == 0){
A[m-1]=B[m-1];
m--;
}else{
A[m+n-1] = A[n-1]>B[m-1]? A[--n]:B[--m];
}
}
return A;
}
}