Leetcode 1 最小的k个数
题目要求:输入整数数组 arr
,找出其中最小的 k
个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
此问题简单思路是排序, 我们分别利用直接插入排序,归并,快排, 堆排序来实现!
直接插入排序, 时间复杂度O(n^2), 空间复杂度为O(1), 优化措施可以通过二分法来减少比较次数。
** * 直接插入法 容易把条件tempt<arr[j]变为条件arr[i]<arr[j] **/ public void directInsertOrderSort(int[] arr) { int tempt = 0, j = 0; for (int i = 1; i < arr.length; i++) { tempt = arr[i];
// 可以优化利用二分法减少比较次数 for (j = i - 1; j >= 0 && tempt < arr[j]; j--) { arr[j + 1] = arr[j]; } arr[j + 1] = tempt;
} }
二分查找优化, 虽然减少比较次数,在数据比较少的情况下时间复杂度还是很高。
// 之前 0, i-1都是有序元素 int low = 0, high = i - 1; while (low <= high) { // 二分查找优化 int mid = (low + high) / 2; if (arr[mid] >= tempt) high = mid - 1; else low = mid + 1; } for (j = i - 1; j >= high + 1; j++) { arr[j + 1] = arr[j]; } arr[high + 1] = tempt;
快速排序------递归和非递归 平均时间复杂度O(nlogn), 如果数据基本有序,那么时间复杂度为O(n^2),空间复杂度最优是O(logn), 每次从中间分割. 最坏为O(n) 变成冒泡排序
/** * * 快速排序 **/ public void directQuickOrderSort(int[] arr, int low, int high) { /*if (low < high) { int mid = rQuickMindIndex(arr, low, high); directQuickOrderSort(arr, low, mid - 1); directQuickOrderSort(arr, mid + 1, high); }*/ Stack<Integer> stack = new Stack<>(); if (low < high) { // 非递归 stack.push(high); stack.push(low); while (!stack.isEmpty()) { low = stack.pop(); high = stack.pop(); int mid = rQuickMindIndex(arr, low, high); if (mid - 1 > low) { stack.push(mid - 1); stack.push(low); } if (mid + 1 < high) { stack.push(high); stack.push(mid + 1); } } } } public int rQuickMindIndex(int arr[], int low, int high) { int tempt = arr[low]; // 保存当前需要替换的值 while (low < high) { // while (high > low && arr[high] >= tempt) high--; arr[low] = arr[high]; while (low < high && arr[low] < tempt) low++; arr[high] = arr[low]; } arr[low] = tempt; return low; }
堆排序----> 此种方法是查找前k个数的最好方法, 空间复杂度为O(1), 首先维护一个k个元素的大顶堆,然后利用淘汰策略一个一个淘汰,组后输出这个堆。
/** * 堆排序 构建k个元素的大顶堆包括两步 堆调整, * */ public void directHeapOrderSort(int[] arr, int k) { for (int i = k/ 2 - 1; i >= 0; i--) { // 调整数组中从i,.....len-1中数据使满足堆排序结构 heapAdjust(arr, i, k); } } /** * 大顶堆的调整, * @param arr 数组 * @param index 需要调整的元素索引位置 * @param high 堆的元素个数 */ public void heapAdjust(int[] arr, int index, int high) { // 保存此位置上的数据信息 int tempt = arr[index]; for (int i = index * 2 + 1; i < high; i = i * 2 + 1) { if (i + 1 < high && arr[i + 1] > arr[i]) i++; //满足右边节点数据更小 // 比较数据和index位置上数据的大小 if (tempt < arr[i]) { arr[index] = arr[i]; index = i; } else break; } arr[index] = tempt; }
归并排序 时间复杂度O(nlogn), 空间O(n), 需要一个辅助的拷贝数组空间。
public void directReclusiveOrderSort(int[] arr, int[] copy, int low, int high) { if (low >= high) return; int mid = (low + high) / 2; directReclusiveOrderSort(arr, copy, low, mid); directReclusiveOrderSort(arr, copy, mid + 1, high); directReclusiveAllToOneOrder(arr, copy, low, mid, high); } public void directReclusiveAllToOneOrder(int[] arr, int[] copy, int low, int mid, int high) { // 先每次新创建一个数组, 后期修改未全局创建一个数组 //int[] copy=new int[1+high-low]; int l1 = low, l2 = mid + 1, index = low; while (l1 <= mid && l2 <= high) { if (arr[l1] > arr[l2]) { copy[index++] = arr[l2++]; } else { copy[index++] = arr[l1++]; } } while (l1 <= mid) { copy[index++] = arr[l1++]; } while (l2 <= high) { copy[index++] = arr[l2++]; } for (int i = low; i <= high; i++) { arr[i] = copy[i]; } }