笔试面试算法经典-打印n个数组中最大的topk

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

【题目】
有n个长度不一的数组,所有的数组都是有序的,请从大到小一次打印出这n个数组整体最大的 k 个数,如果 k大于n个数组中元素则将数组的元素全部打印。输入n行长度不等的二维数组可以表示n个长度不同的一维数组。

例如:输入matrix={{1 , 2, 3 }, {4 , 5 }, {6 ,7 ,8 ,9 }, { 10 }}; k=4,输出:10,9,8,7。

思路

  1. 建立一个大小为n的大根堆,将每个数组的最后一个元素插入到堆中,这个过程就是建立初始堆。

  2. 建立好初始堆后,堆顶元素就是最大值,打印堆顶元素。

  3. 如果堆顶元素来自哪个数组,就将数组中的下一个元素放到堆顶,然后调整堆为大根堆。如果数组已经遍历完,就选择堆的最后一个元素放到堆顶,堆的大小减1。

  4. 这样每次都能获得n个数组剩余元素的最大值,循环遍历k次打印k个值,在遍历的过程中如果堆的大小为0则停止,此时数组中的元素已经遍历完。

  5. 由于要知道数组中每个元素所处在哪个数组中(行号),以及在数组中的位置(列号),定义一个新的节点类型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时,所有的元素都取完了停止遍历。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值