top K

求一个数组中最小的K个数

思路1:利用快排的思想

思路2:利用堆的思想

 

1:快排思想

快排的核心是patition,该函数返回的是基准在该趟排序后的位置,并且能保证在该下标之前的所有元素都不比它大,在下标之后的所有元素都不比它小。

假设取k=4,n=10,如果patiton返回的index恰好为4

此时数组[a1,a2,a3,a4,X,b1,b2,b3,b4,b5],此时前k小元素就是index<4之前的那4个元素,递归结束(an<=X && bn>=X)

如果patition返回的index大于4(比如说5)

此时数组[a1,a2,a3,a4,a5,X,b1,b2,b3],则继续对左边进行patition

同理index小于4时,则继续对右边进行patition

 

patition的实现采用填坑法:

1:取数组第一个位置为基准,先保存该基准,并挖坑。

2:从数组尾开始找第一个小于该基准的值填上旧坑,并且该位置变成新的坑

3:从数组头开始找第一个大于该基准的值填上旧坑,并且该位置变成新的坑

重复2~3直到i>=j为止

eg:

[ 3 , 2 , 7 , 6 , 6 , 1 , 2 , 5 ]  temp=3

 

[ 坑 , 2 , 7 , 6 , 6 , 1 , 2 , 5 ]   找到第一个小于基准3的数2

   i                                   j

[  2 , 2 , 7 , 6 , 6 , 1 , 坑  , 5 ]   找到第一个大于基准3的数7

   i                              j

[  2 , 2 , 坑 , 6 , 6 , 1 , 7  , 5 ]   找到第一个小于基准3的数1

              i                    j

[  2 , 2 , 1 , 6 , 6 , 坑 , 7  , 5 ]   找到第一个大于基准3的数6

              i              j

[  2 , 2 , 1 , 坑 , 6 , 6 , 7  , 5 ]   在i<j的情况下,从右边往左边已经找到小于基准3的数了

                   i          j

[  2 , 2 , 1 , 3 , 6 , 6 , 7  , 5 ]   将基准3填在最后的坑上,此时保证index<3的数都不大于3,index>3的数都不小于3

    public static int patition(int[] nums, int left, int right) {
		int temp = nums[left];
		while (left < right) {
			while (left < right && nums[right] >= temp) {
				right--;
			}
			if (left < right) {
				nums[left] = nums[right];
			}
			while (left < right && nums[left] <= temp) {
				left++;
			}
			if (left < right) {
				nums[right] = nums[left];
			}
		}
		nums[left] = temp;
		return left;
	}
    public static void main(String[] args) {
		int[] nums = { 1, 2, 4, 3, 9, 7, 6, 8, 5, 9, 6 };
		int k = 4;
		int index = 0;
		int left = 0;
		int right = nums.length - 1;
		while (index >= 0 && index < nums.length) {
			index = patition(nums, left, right);
			if (index == k) {
				System.out.println("使用patition方法求TOP_K_MIN:");
				for (int i = 0; i < index; i++)
					System.out.print(nums[i] + " ");
				System.out.println();
				break;
			} else if (index > k) {
				right = index - 1;
			} else {
				left = index + 1;
			}
		}
    }
		

2:堆的思想

同样以k=4、n=10为例,在长度为10的数组中找最小的4个

先取下标为0~3的元素,创建一个大顶堆max_heap

 此时max_heap[0]为数组前4元素中的最大值

再遍历下标4~9的元素,如果有比max_heap[0]小,则insert

insert操作实际是把新元素覆盖到堆顶,然后进行堆调整,使其满足大顶堆性质

    
    public static int[] getTopKByHeap(int input[], int k) {
        int heap[] = createHeap(input, k);
        for (int i = k; i < input.length; i++) {
            if (input[i] < heap[0]) {
                insert(heap, input[i]);
		    }
	    }
	    return heap;
    }

    public static int[] createHeap(int a[], int k) {
		int[] result = new int[k];
		for (int i = 0; i < k; i++) {
			result[i] = a[i];
		}
		for (int i = 1; i < k; i++) {
			int child = i;
			int parent = (i - 1) / 2;
			int temp = a[i];
			while (parent >= 0 && child != 0 && result[parent] < temp) {
				result[child] = result[parent];
				child = parent;
				parent = (parent - 1) / 2;
			}
			result[child] = temp;
		}
		return result;
	}

    public static void insert(int a[], int value) {
        a[0] = value;
        int parent = 0;
        while (parent < a.length) {
            int lchild = 2 * parent + 1;
		    int rchild = 2 * parent + 2;
		    int minIndex = parent;
		    if (lchild < a.length && a[parent] < a[lchild]) {
			    minIndex = lchild;
		    }
		    if (rchild < a.length && a[minIndex] < a[rchild]) {
			    minIndex = rchild;
		    }
		    if (minIndex == parent) {
			    break;
		    } else {
			    int temp = a[parent];
			    a[parent] = a[minIndex];
			    a[minIndex] = temp;
			    parent = minIndex;
		    }
	    }
    }
public static void main(String[] args) {
		int[] nums = { 1, 2, 4, 3, 9, 7, 6, 8, 5, 9, 6 };
		int k = 4;
		int result[] = getTopKByHeap(nums, k);
		System.out.println("使用max_heap方法求TOP_K_MIN:");
		for (int i = 0; i < result.length; i++) {
			System.out.print(result[i] + " ");
		}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值