题目信息
LeetoCode地址: . - 力扣(LeetCode)
题目理解
题意简单且直观,而且是很经典的考验快速排序以及堆排序的算法题,很考验基本功。
堆排序写法
对points数组原地建立小顶堆
并依次弹出第1个元素,重新调整堆顶元素,再弹出第1个。。。直到弹出前K个元素。
时间复杂度: O(nlogn)
额外空间复杂度:O(k)
class Solution {
int[][] points;
public int[][] kClosest(int[][] points, int k) {
this.points = points;
buildMinHeap(points, points.length);
int[][] res = new int[k][2];
int lastIndex =points.length-1;
for (int i = 0; i<k; i++) {
res[i] = points[0];
swap(0, lastIndex--);
minHeapify(0, lastIndex+1);
}
return res;
}
public void buildMinHeap(int[][] points, int length) {
for (int i = points.length/2; i>=0; i--) {
minHeapify(i, length);
}
}
public void minHeapify(int i, int length) {
int l = i*2+1, r = i*2+2;
int min = i;
int minLength = points[i][0]*points[i][0] + points[i][1]*points[i][1];
int lMinLength = l < length ? points[l][0]*points[l][0] +points[l][1] * points[l][1] : Integer.MAX_VALUE;
int rMinLength = r < length ? points[r][0]*points[r][0] +points[r][1] * points[r][1] : Integer.MAX_VALUE;
if (lMinLength < minLength) {
min = l;
minLength = lMinLength;
}
if (rMinLength < minLength) {
min = r;
}
if (i != min) {
swap(i, min);
minHeapify(min, length);
}
}
void swap(int a, int b) {
int[] tmp = points[a];
points[a] = points[b];
points[b] = tmp;
}
}
快速排序写法
普通的写法是直接对整个数组排序,然后取前k个元素,然而这不是最高效的。
由于我们仅需要前k个元素,而且不关注顺序,因此可以省略到k之后元素的顺序。
假如我们当前左右边界分别是l和r,在快排中间步骤中,确认了j位置元素的值后,如果发现k <= j, 则无需再关注j到r之间元素的排序结果;
类似的,假如k > j, 那我们也无需再关注l到j之间的元素,因为我们已经确认了他们必定会出现在最终结果集中。
时间复杂度:O(n), 由于我们没有进行任何多余元素的排序动作。
额外空间复杂度:O(1), 我们是在原地进行排序,没有使用额外空间。
int k;
int[][] points;
public int[][] kClosest(int[][] points, int k) {
this.k = k;
this.points = points;
quickSort(0, points.length-1);
return Arrays.copyOfRange(points, 0, k);
}
public void quickSort(int l, int r) {
if (l == r) {
return;
}
int i = l-1, j = r+1;
int[] mid = points[l+ (r-l)/2];
while (i < j) {
while (compare(mid, points[++i]));
while (compare(points[--j], mid));
if (i < j) {
swap(i, j);
}
}
if (j >= k) {
quickSort(l, j);
} else if (k >= j+1) {
quickSort(j+1, r);
}
}
boolean compare(int[] a, int[] b) {
return (a[0]*a[0] + a[1]*a[1]) > (b[0]*b[0] + b[1]*b[1]);
}
void swap(int a, int b) {
int[] tmp = points[a];
points[a] = points[b];
points[b] = tmp;
}