💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 1. 题目描述 给定一个几乎有序的数组,几乎有序是指如果把数组排好序,每个元素移动的距离不超过`K`,并且`K`相对于数组的长度是比较小的。请选择一个合适的算法来堆这个数组进行排序。 # 2. 题解 因为如果将数组排好序,每个元素移动的距离不超过`K`。比如排序好的数组`arr=[2, 5, 6, 8, 10, 15, 16, 19, 21]`,假定此时`K=3`那么这个几乎有序数组可以为:`[8, 2, 5, 6, 10, 19, 21, 16, 15]`。 因为每个元素移动的距离不超过`K`,换句话说也就是我们只从左到右遍历,保证对扫描到的元素`K+1`个元素进行排序,保证首个元素为最小值即可。所以可以建立一个大小为`K+1`的小根堆来解决这个问题。 ~~~ public class HeapSortExtend { public static void main(String[] args) { int[] arr = new int[]{8, 2, 5, 6, 10, 19, 21, 16, 15}; new HeapSortExtend().sortByHeap(arr, 3); for (int i : arr) { System.out.print(i+"\t"); } } private void sortByHeap(int[] arr, int K){ // 定义小根堆 PriorityQueue<Integer> heap = new PriorityQueue<Integer>(); int heapSize = K + 1; int i = 0; for (; i < heapSize; i++) { heap.add(arr[i]); } int j = 0; for (; i < arr.length; j++) { heap.add(arr[i++]); arr[j] = heap.poll(); } while(!heap.isEmpty()){ arr[j++] = heap.poll(); } } } ~~~ <img src='http://weizu_cool.gitee.io/gif-source/images/屏幕截图 2022-01-06 103310.png'/> 当然,这里也可以来仿写一下`PriorityQueue`: ~~~ static class MinHeap{ private int[] arr; private int index = 0; public MinHeap(){ this(512); } public MinHeap(int cap){ arr = new int[cap]; } public void add(int val){ arr[index++] = val; for (int i = 0; i < index; i++) { heapInsert(i); } } public boolean isEmpty(){ return index == 0; } public int poll(){ int val = arr[0]; int size = --index; swap(arr, 0, size); // 和最后一个交换 // 保证继续是小根堆 heapify(size); return val; } private void heapify(int size) { int i = 0, left = 1; while(left < size){ int minest = left + 1 < size && arr[left] > arr[left + 1] ? left + 1: left; minest = arr[i] < arr[minest] ? i : minest; if(minest == i) break; swap(arr, i, minest); i = minest; left = i * 2 + 1; } } private void heapInsert(int i) { while(arr[i] < arr[(i - 1) / 2]){ swap(arr, i, (i - 1) / 2); i = (i - 1) / 2; } } private void swap(int[] arr, int left, int right) { int temp = arr[left] ^ arr[right]; arr[left] = arr[left] ^ temp; arr[right] = arr[left] ^ temp; } } ~~~ 替换`PriorityQueue`替换即可。