【题目】
有n个长度不一的数组,所有的数组都是有序的,请从大到小一次打印出这n个数组整体最大的 k 个数,如果 k大于n个数组中元素则将数组的元素全部打印。输入n行长度不等的二维数组可以表示n个长度不同的一维数组。
例如:输入matrix={{1 , 2, 3 }, {4 , 5 }, {6 ,7 ,8 ,9 }, { 10 }}; k=4,输出:10,9,8,7。
思路:
建立一个大小为n的大根堆,将每个数组的最后一个元素插入到堆中,这个过程就是建立初始堆。
建立好初始堆后,堆顶元素就是最大值,打印堆顶元素。
如果堆顶元素来自哪个数组,就将数组中的下一个元素放到堆顶,然后调整堆为大根堆。如果数组已经遍历完,就选择堆的最后一个元素放到堆顶,堆的大小减1。
这样每次都能获得n个数组剩余元素的最大值,循环遍历k次打印k个值,在遍历的过程中如果堆的大小为0则停止,此时数组中的元素已经遍历完。
- 由于要知道数组中每个元素所处在哪个数组中(行号),以及在数组中的位置(列号),定义一个新的节点类型node。
下面是:matrix={{1 , 2, 3 }, {4 , 5 }, {6 ,7 ,8 ,9 }, { 10 }}; k=4,对应的算法图:
① 选择每一行中的最后一个元素建立大根堆
②输出堆顶元素如果选择堆顶元素同一行的下一个元素放到堆顶,如果同一行中没有元素,则选择堆中的最后一个元素代替此时堆大小减1。上图中10同一行的没有元素选择堆最后一个元素3放到堆顶,然后调整堆为大根堆。
③重复过程2输出堆顶元素如果选择堆顶元素同一行的下一个元素放到堆顶,如果同一行中没有元素,则选择堆中的最后一个元素代替此时堆大小减1。上图中9同一行的下一个元素是8选择8放到堆顶,然后调整堆为大根堆。
④如果堆的大小为0则停止,说明元素的个数小于k。否则继续遍历直到输出k个元素。
代码
package Arrays;
public class MaxKInNArrays {
public static void main(String[] args) {
int[][] matrix={{1,2,3},{4,5},{6,7,8,9},{10}};
int k=10;
maxKInNArrays(matrix,k);
}
//函数maxKInNArrays(int[][] matrix,int k):找出n个数组中最大的k个元素
public static void maxKInNArrays(int[][] matrix,int k)
{
if(matrix==null||matrix.length==0)
return;
int n=matrix.length;
node arr[]=new node[n];
int heapsize=n;
//heapsize 代表初始堆的大小
for(int i=0;i<n;i++)
{
node node=new node(i,matrix[i].length-1,matrix[i][matrix[i].length-1]);
// node(int col,int index,int val)
arr[i]=node;
heapInsert(arr,i);
//将节点插入到堆中建立大小为n的大根堆
}
for(int j=0;j<k;j++)
{
if(heapsize==0)
break;
//如果heapsize=0,则可知n数组中的元素已经遍历完,且元素的个数小于k停止
System.out.print(arr[0].val+" ");
node temp=arr[0];
if(temp.index>0)
{
//node(int col,int index,int val)
node node=new node(temp.col,--temp.index,matrix[temp.col][temp.index]);
arr[0]=node;
//如果数组的下一个元素不为null则将其放到堆顶。
}
else if(temp.index==0)
{
arr[0]=arr[--heapsize];
//如果数组的下一个元素为null 则将堆尾的元素放到堆顶,heapsize--;
}
heapify(arr, heapsize, 0);
}
}
//开始时使用插入堆进行堆化
public static void heapInsert(node arr[],int n)
{
int index=(n-1)/2;
while(index>=0&&arr[n].val>arr[index].val)
{
swap(arr, index, n);
n=index;
index=(index-1)/2;
}
}
public static void heapify(node arr[],int n,int i)
{//调整堆,始终保持最大堆。
int left=2*i+1,right=2*i+2,largest=i;
while(left<n)
{
if(arr[left].val>arr[largest].val)
largest=left;
if(right<n&&arr[right].val>arr[largest].val)
largest=right;
//right>=n时右孩子不用判断,因为右孩子在堆外面
if(largest!=i)
{
swap(arr, largest, i);
}
else {
break;
}
i=largest;
left=2*i+1;
right=2*i+2;
}
}
public static void swap(node arr[],int i,int j)
{
node temp;
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
class node{
int col;
int index;
int val;
public node(int col,int index,int val)
{
this.col=col;
this.index=index;
this.val=val;
}
}
注意:heapsize初始时定义为n是为了能从n个数组中取到数,heapsize-1,之后表示只能在heapsize-1个数组中取元素,当heapsize=0时,所有的元素都取完了停止遍历。

本文介绍了一种从多个有序数组中寻找最大的K个数的方法,通过构建大根堆实现高效查找。
927

被折叠的 条评论
为什么被折叠?



