题目1:求无序数组第k小的数

可采用改写快排的方式,也可采用bfprt算法

  1. // 算法1:使用大根堆,时间复杂度O(n*logk)
  2. public static int findKthMinNum1(int[] arr, int k) {
  3. PriorityQueue<Integer> maxHeap = new PriorityQueue<>((i1, i2) -> i2 - i1);
  4. for (int i = 0; i < k; i++) {
  5. maxHeap.offer(arr[i]);
  6. }
  7. for (int i = k; i < arr.length; i++) {
  8. if (arr[i] < maxHeap.peek()) {
  9. maxHeap.poll();
  10. maxHeap.offer(arr[i]);
  11. }
  12. }
  13. return maxHeap.peek();
  14. }
  1. public static int findKthMinNum2(int[] arr, int k) {
  2. return process(copyArr(arr), 0, arr.length - 1, k - 1);
  3. }
  4. private static int[] copyArr(int[] arr) {
  5. return Arrays.copyOf(arr, arr.length);
  6. }
  7. private static int process(int[] arr, int l, int r, int index) {
  8. if (l == r) {
  9. return arr[l];
  10. }
  11. int pivot = arr[l + (int) (Math.random() * (r - l + 1))];
  12. int[] range = partition(arr, l, r, pivot);
  13. if (index >= range[0] && index <= range[1]) {
  14. return arr[index];
  15. } else if (index < range[0]) {
  16. return process(arr, l, range[0] - 1, index);
  17. } else {
  18. return process(arr, range[1] + 1, r, index);
  19. }
  20. }
  21. public static int[] partition(int[] arr, int l, int r, int pivot) {
  22. int less = l - 1;
  23. int more = r + 1;
  24. int cur = l;
  25. while (cur < more) {
  26. if (arr[cur] < pivot) {
  27. swap(arr, ++less, cur++);
  28. } else if (arr[cur] > pivot) {
  29. swap(arr, cur, --more);
  30. } else {
  31. cur++;
  32. }
  33. }
  34. return new int[]{less + 1, more - 1};
  35. }
  36. private static void swap(int[] arr, int i1, int i2) {
  37. int tmp = arr[i1];
  38. arr[i1] = arr[i2];
  39. arr[i2] = tmp;
  40. }
  1. public static int findKthMinNum3(int[] arr, int k) {
  2. return bfprt(copyArr(arr), 0, arr.length - 1, k - 1);
  3. }
  4. public static int bfprt(int[] arr, int l, int r, int index) {
  5. if (l == r) {
  6. return arr[l];
  7. }
  8. // L...R 每五个数一组
  9. // 每一个小组内部排好序
  10. // 小组的中位数组成新数组
  11. // 这个新数组的中位数返回
  12. int pivot = medianOfMedian(arr, l, r);
  13. int[] range = partition(arr, l, r, pivot);
  14. if (index >= range[0] && index <= range[1]) {
  15. return arr[index];
  16. } else if (index < range[0]) {
  17. return bfprt(arr, l, range[0] - 1, index);
  18. } else {
  19. return bfprt(arr, range[1] + 1, r, index);
  20. }
  21. }
  22. /**
  23. * 以5位元素为一组,排序,获取每组的中点,组成新的一组,返回新组的中点
  24. */
  25. public static int medianOfMedian(int[] arr, int l, int r) {
  26. int size = r - l + 1;
  27. int offset = size % 5 == 0 ? 0 : 1;
  28. int mSzie = size / 5 + offset;
  29. int[] mArr = new int[mSzie];
  30. for (int team = 0; team < mSzie; team++) {
  31. int teamFirst = l + team * 5;
  32. mArr[team] = getMedian(arr, teamFirst, Math.min(r, teamFirst + 4));
  33. }
  34. return bfprt(mArr, 0, mSzie - 1, mArr.length >> 1);
  35. }
  36. public static int getMedian(int[] arr, int l, int r) {
  37. insertionSort(arr, l, r);
  38. return arr[l + ((r - l) >> 1)];
  39. }
  40. public static void insertionSort(int[] arr, int l, int r) {
  41. for (int i = l + 1; i <= r; i++) {
  42. for (int j = i - 1; j >= l && arr[j] > arr[j + 1]; j--) {
  43. swap(arr, j, j + 1);
  44. }
  45. }
  46. }
  47. public static int[] partition(int[] arr, int l, int r, int pivot) {
  48. int less = l - 1;
  49. int more = r + 1;
  50. int cur = l;
  51. while (cur < more) {
  52. if (arr[cur] < pivot) {
  53. swap(arr, ++less, cur++);
  54. } else if (arr[cur] > pivot) {
  55. swap(arr, cur, --more);
  56. } else {
  57. cur++;
  58. }
  59. }
  60. return new int[]{less + 1, more - 1};
  61. }
  62. private static void swap(int[] arr, int i1, int i2) {
  63. int tmp = arr[i1];
  64. arr[i1] = arr[i2];
  65. arr[i2] = tmp;
  66. }

题目2:返回topk个最大的数

给定一个无序数组arr中,长度为N,给定一个正数k,返回topk个最大的数

 //排序+收集 时间复杂父 O(n*logN)

    public static int[] getTopK1(int[] arr, int k) {
        if (arr == null || arr.length == 0) {
            return new int[0];
        }
        int n = arr.length;
        k = Math.min(n, k);
        Arrays.sort(arr);
        int[] res = new int[k];

        for (int i = n - 1, j = 0; j < k; i--, j++) {
            res[j] = arr[i];
        }
        return res;
    }
// 使用了堆结构,时间复杂度O(n+K*logn)

public static int[] getTopK2(int[] arr, int k) {
    if (arr == null || arr.length == 0) {
        return new int[0];
    }
    int n = arr.length;

    for (int i = n - 1; i >= 0; i--) {
        heapify(arr, i, n);
    }

    int heapSize = n;

    int count = 0;
    while (heapSize > 0 && count < k) {
        swap(arr, 0, --heapSize);
        heapify(arr, 0, heapSize);
        count++;
    }


    k = Math.min(n, k);
    int[] res = new int[k];
    for (int i = n - 1, j = 0; j < k; i--, j++) {
        res[j] = arr[i];
    }
    return res;
}

private static void heapify(int[] arr, int i, int size) {
    int left = 2 * i + 1;
    while (left < size) {
        int bigIndex = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
        bigIndex = arr[i] >= arr[bigIndex] ? i : bigIndex;
        if (bigIndex == i) {
            break;
        }
        swap(arr, i, bigIndex);
        i = bigIndex;
        left = 2 * i + 1;
    }
}

private static void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
// 时间复杂度O(N+k*logk)
public static int[] getTopK3(int[] arr, int k) {
    if (arr == null || arr.length == 0) {
        return new int[0];
    }
    int n = arr.length;
    k = Math.min(k, n);

    int num = minK(arr, n - k);
    int[] res = new int[k];

    int index = 0;
    for (int i = 0; i < n; i++) {
        if (arr[i] > num) {
            res[index++] = arr[i];
        }
    }

    for (; index < k; index++) {
        res[index] = num;
    }
    Arrays.sort(res);
    for (int l = 0, r = k - 1; l < r; l++, r--) {
        swap(res, l, r);  
    }
    return res;
}

private static int minK(int[] arr, int i) {

    return bfprt(Arrays.copyOf(arr, arr.length), i - 1);

}

private static int bfprt(int[] arr, int index) {

    int l = 0;
    int r = arr.length - 1;
    while (l < r) {
        int pivot = medianOfMedian(arr, l, r);
        int[] range = partition(arr, l, r, pivot);
        if (index >= range[0] && index <= range[1]) {
            return arr[index];
        } else if (index < range[0]) {
            r = range[0] - 1;
        } else {
            l = range[1] + 1;
        }
    }
    return arr[l];

}

private static int[] partition(int[] arr, int l, int r, int pivot) {
    int less = l - 1;
    int more = r + 1;
    int cur = l;
    while (cur < more) {
        if (arr[cur] < pivot) {
            swap(arr, ++less, cur++);
        } else if (arr[cur] > pivot) {
            swap(arr, cur, --more);
        } else {
            cur++;
        }
    }
    return new int[]{less + 1, more - 1};
}

private static int medianOfMedian(int[] arr, int l, int r) {
    int size = r - l + 1;
    int offset = size % 5 == 0 ? 0 : 1;
    int mSzie = size / 5 + offset;
    int[] mArr = new int[mSzie];
    for (int team = 0; team < mSzie; team++) {
        int teamFirst = l + team * 5;
        mArr[team] = median(arr, teamFirst, Math.min(r, teamFirst + 4));
    }
    return mArr[mSzie >> 1];
}

private static int median(int[] arr, int l, int r) {
    insertSort(arr, l, r);
    return arr[l + ((r - l) >> 1)];
}

private static void insertSort(int[] arr, int l, int r) {
    for (int i = l + 1; i <= r; i++) {
        for (int j = i - 1; j >= l && arr[j + 1] < arr[j]; j--) {
            swap(arr, j, j + 1);
        }
    }
}

private static void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}