topk 堆

https://blog.youkuaiyun.com/juzihongle1/article/details/70212243

堆(Heap)、堆排序和TopK
https://www.cnblogs.com/eudiwffe/p/6202111.html
《排序算法》——堆排序(大顶堆,小顶堆,Java)
https://blog.youkuaiyun.com/Gamer_gyt/article/details/47143987

大顶堆和小顶堆–Java版
https://blog.youkuaiyun.com/silentwolfyh/article/details/77099258
PriorityQueue
https://www.cnblogs.com/gnivor/p/4841191.html

堆排序和topk不完全一样,topk在建堆之后是不排序的,大顶堆里是数组里最小的k个数,小顶堆里是数组里最大的k个数,只有arr[0]是topk,其余的都是无序的,堆排序需要在建堆之后进行排序,整个数组才会有序

这个方法的时间复杂度是多少呢?

1.构建堆的时间复杂度是 O(k)
2.遍历剩余数组的时间复杂度是O(n-k)
3.每次调整堆的时间复杂度是 O(logk)

其中2和3是嵌套关系,1和2,3是并列关系,所以总的最坏时间复杂度是O((n-k)logk + k)。当k远小于n的情况下,也可以近似地认为是O(nlogk)。

这个方法的空间复杂度是多少呢?

刚才我们在详细步骤中把二叉堆单独拿出来演示,是为了便于理解。但如果允许改变原数组的话,我们可以把数组的前k个元素“原地交换”来构建成二叉堆,这样就免去了开辟额外的存储空间。

因此,方法的空间复杂度是O(1)。

topk

public static void heapSort(int[] array,int k) {
		if (array == null || array.length == 0)
			return;
		
		buildHeap(array,k); // 第一次排序,构建最大堆,只保证了堆顶元素是数组里最大的
		
		for (int i = k; i < array.length; i++) {
			if (array[i]<array[0]) {
				swap(array, i, 0);
				buildHeap(array,k);
				
			}
		}
		
	}
	public static void buildHeap(int[] array,int k) {
		if (array == null || array.length == 1)
			return;
		
		// 堆的公式就是 int root = 2*i, int left = 2*i+1, int right = 2*i+2;
		int cursor = k / 2-1;
		for (int i = cursor; i >= 0; i--) { // 这样for循环下,就可以第一次排序完成
			maxHeap(array, k, i);
//			minHeap(array, k, i);
		}
	}

堆排序

public static void heapSort(int[] array) {
		if (array == null || array.length == 1)
			return;

		buildHeap(array); // 第一次排序,构建最大堆,只保证了堆顶元素是数组里最大的

		for (int i = array.length - 1; i >= 0; i--) {
			// 这个是什么意思呢?,经过上面的一些列操作,目前array[0]是当前数组里最大的元素,需要和末尾的元素交换
			// 然后,拿出最大的元素
			swap(array, 0, i);

			// 交换完后,下次遍历的时候,就应该跳过最后一个元素,也就是最大的那个值,然后开始重新构建最大堆
			// 堆的大小就减去1,然后从0的位置开始最大堆
			 maxHeap(array, i, 0);
//			minHeap(array, i, 0);
		}
	}
// 构建堆
	public static void buildHeap(int[] array) {
		if (array == null || array.length == 1)
			return;

		// 堆的公式就是 int root = 2*i, int left = 2*i+1, int right = 2*i+2;
		int cursor = array.length / 2-1;
		for (int i = cursor; i >= 0; i--) { // 这样for循环下,就可以第一次排序完成
			 maxHeap(array, array.length, i);
//			minHeap(array, array.length, i);
		}
	}

大顶堆

public static void maxHeap(int[] array, int heapSieze, int index) {
		int left = index * 2 + 1; // 左子节点
		int right = index * 2 + 2; // 右子节点
		int maxValue = index; // 暂时定在Index的位置就是最大值

		// 如果左子节点的值,比当前最大的值大,就把最大值的位置换成左子节点的位置
		if (left < heapSieze && array[left] > array[maxValue]) {
			maxValue = left;
		}

		// 如果右子节点的值,比当前最大的值大,就把最大值的位置换成右子节点的位置
		if (right < heapSieze && array[right] > array[maxValue]) {
			maxValue = right;
		}

		// 如果不相等,说明啊,这个子节点的值有比自己大的,位置发生了交换了位置
		if (maxValue != index) {
			swap(array, index, maxValue); // 就要交换位置元素

			// 交换完位置后还需要判断子节点是否打破了最大堆的性质。最大堆性质:两个子节点都比父节点小。
			maxHeap(array, heapSieze, maxValue);
		}
	}

小顶堆

public static void minHeap(int[] array, int heapSieze, int index) {
		int left = index * 2 + 1; // 左子节点
		int right = index * 2 + 2; // 右子节点
		int maxValue = index; // 暂时定在Index的位置就是最小值

		// 如果左子节点的值,比当前最小的值小,就把最小值的位置换成左子节点的位置
		if (left < heapSieze && array[left] < array[maxValue]) {
			maxValue = left;
		}

		// 如果右子节点的值,比当前最小的值小,就把最小值的位置换成左子节点的位置
		if (right < heapSieze && array[right] < array[maxValue]) {
			maxValue = right;
		}

		// 如果不相等,说明啊,这个子节点的值有比自己小的,位置发生了交换了位置
		if (maxValue != index) {
			swap(array, index, maxValue); // 就要交换位置元素

			// 交换完位置后还需要判断子节点是否打破了最小堆的性质。最小性质:两个子节点都比父节点大。
			minHeap(array, heapSieze, maxValue);
		}
	}

交换函数:必须要把arr传入才会改变arr,否则进去的是值,不是引用

public static void swap(int[] array, int index1, int index2) {
		int temp = array[index1];
		array[index1] = array[index2];
		array[index2] = temp;
	}

K Closest Points to Origin
We have a list of points on the plane. Find the K closest points to the origin (0, 0).

(Here, the distance between two points on a plane is the Euclidean distance.)

You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in.)

Example 1:

Input: points = [[1,3],[-2,2]], K = 1
Output: [[-2,2]]
Explanation:
The distance between (1, 3) and the origin is sqrt(10).
The distance between (-2, 2) and the origin is sqrt(8).
Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin.
We only want the closest K = 1 points from the origin, so the answer is just [[-2,2]].
Example 2:

Input: points = [[3,3],[5,-1],[-2,4]], K = 2
Output: [[3,3],[-2,4]]
(The answer [[-2,4],[3,3]] would also be accepted.)

public int[][] kClosest(int[][] points, int K) {
// 优先队列就是堆,传入的是比较器,由于是和原点比较,所以用的是x1^2+y1^2-(x2^2+y2^2)
        PriorityQueue<int[]> pq = new PriorityQueue<int[]>((p1, p2) ->p2[0] * p2[0] + p2[1] * p2[1] - p1[0] * p1[0] - p1[1] * p1[1]);
    	    for (int[] p : points) {
    	        pq.offer(p);
    	        if (pq.size() > K) {
    	            pq.poll();
    	        }
    	    }
    	    int[][] res = new int[K][2];
    	    while (K > 0) {
    	        res[--K] = pq.poll();
    	    }
    	    return res;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值