从N个数中选最小的K个数

    技术2026-01-14  4

     

     

     

    声明:题目来自: http://blog.csdn.net/v_JULY_v/archive/2010/11/17/6015165.aspx   JULY整理了100道微软等公司的面试题目,我想先不看答案: http://blog.csdn.net/v_JULY_v/archive/2011/01/10/6126406.aspx  自己先做一遍。

     

    题目:

    5. 查找最小的k 个元素

    题目:输入n 个整数,输出其中最小的k 个。

    例如输入1 ,2 ,3 ,4 ,5 ,6 ,7 和8 这8 个数字,则最小的4 个数字为1 ,2 ,3 和4 。

     

    思路:

     

    最简单的想法就是在内部分配一个K大小的数组,用于存储最小的K个数,这K个数从大到小排序 array[0..K-1],那么每次读入一个新的数 elem, 我们比较elem 和 array[0], 如果elem>array[0], 则elem肯定不是最小的K个数的候选,否则(当elem<array[0]),我们找到第一个位置P, 使得array[P-1]>elem>array[P] , 然后: array[i]=array[i+1] for all i =(0..P-2);  array[P-1] = elem.

     

    但是这样并不好,如果给定的数组是从大到小排好顺序的,那么每次我们都要遍历整个内部数组,其时间复杂度是O(N2 ).

     

    其实我们可以把题目重新理解为:

    我需要一个数据结构,

    条件1) 能够在O(1)时间判断一个新的数字是不是已有的K个数字中最大的

    条件2 )  如果不是现有的K个数中最大的话,我希望在最短时间内,丢弃现有K个数中的最大的那个数,放入新的数,并且最适当调整,使调整后的数据结构仍然满足 条件1).

     

    结果就是 最大堆 (Max Binary Heap). 对于Binary Heap,每次调整,最坏情况时间复杂度是 log(k)。 前K个元素不许要调整(因为我还没有开始建立堆结构),剩下N-K个元素,最坏情况为 (N-K)log(K)。

     

    代码:

     

    /*  * 题目:输入n个整数,输出其中最小的k个。    例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。  */ public class MinNPicker {         private int[] m_binaryHeap;     private int m_numberChecked; //indicate how many elements have been checked         public MinNPicker(int size){                 m_numberChecked = 0;         m_binaryHeap = new int[size];     }         public void print(){         for(int i: m_binaryHeap){             System.out.println(i);         }     }         public void add(int[] elems){         for(int i: elems){             add(i);         }     }         public void reset(){         m_numberChecked = 0;             }         public void add(int elem){                 if(m_numberChecked < m_binaryHeap.length){             m_binaryHeap[m_numberChecked++] = elem;                         if(m_numberChecked == m_binaryHeap.length){                 //now let's construct the binary heap                 //for a binary heap of N size, N/2 to N elements are leaf nodes(leaf nodes are already heap)                             int smallestLeaf = m_binaryHeap.length/2;                                 for(int i=smallestLeaf-1; i>=0; i--){                     maxHeapify(m_binaryHeap, i);                 }             }             return;         }                 if(elem < m_binaryHeap[0]){  //0 is the root, also the max element                         m_binaryHeap[0] = elem;             maxHeapify(m_binaryHeap,0);         }     }         private void maxHeapify(int[] array, int index){         //we use a max heap to contain only N elements, everytime we're feed a new element         //if new elem > max elem within heap, we replace that ex-max elem and redo max-heapify                 //our internal array to hold the heap is 0-based, so left-child(i)=2i+1, right-child(i)=2i+2         //maxHeapipy assume that both left child and right child of i are already heap                 int largest = index;                 int size  = array.length;         int left  = index*2 + 1;         int right = index*2 + 2;                 if(left < size && array[index] < array[left]){  //! make sure left < size, otherwise exception             //left child is bigger             largest = left;         }                 //now let's compare the right child and the largest         if(right < size && array[largest] < array[right]){             largest = right;         }                 //only swap when largest != index         if(largest != index){             int tmp = array[index];             array[index] = array[largest];             array[largest] = tmp;                         //because we swap the content between index and largest, it's not sure if the original             //left child/right child tree are still hold heap property             //!!don't forget to recursive call maxHeapify itself             maxHeapify(array,largest);         }                     }         public static void main(String[] args){                 int[] givenElems = {8,7,6,5,4,3,2,1};                 MinNPicker picker = new MinNPicker(4);         picker.add(givenElems);         picker.print();                 System.out.println("-------");         int[] givenElems2 = {1,2,3,4,5,6,7,8};         picker.reset();         picker.add(givenElems2);         picker.print();                             } }

    最新回复(0)