• 查找最小的k 个元素之C#算法实现


    紧接着上一篇微软编程面试100题,这次想解决的是查找最小的K个元素,题目是:输入n 个整数,输出其中最小的k 个。例如输入1,2,3,4,5,6,7 和8 这8 个数字,则最小的4 个数字为1,2,3 和4。

    看到题目的时候我第一反应,这题很简单,使用任何方式的排序将数列按顺序存储,之后遍历需要的k个元素即可,于是自己动手很容易就完成了,但是后来在网络上发现很多人对这题的解决方式是用小根堆(MinHeap)或者大根堆(MaxHeap),这才意识到,其实出题人是醉翁之意不在酒,在乎复杂度的考虑也。

    先写用排序的方式完成题目的方式吧,不仅简单,不需要费太多脑子,重要的是,正好趁这时候复习下排序,这里用快速排序完成:

            public static void Quick_Sort(int[] sort, int left, int right)
            {
                int mid = sort[(left + right) / 2];
                int i = left;
                int j = right;
                do
                {
                    while (sort[i] < mid && i < right) i++;
                    while (sort[j] > mid && j > left) j--;
                    if (i <= j)
                    {
                        int temp = sort[i];
                        sort[i] = sort[j];
                        sort[j] = temp;
                        i++;
                        j--;
                    }
    
                } while (i <= j);
    
                if (j > left) Quick_Sort(sort, left, j);
                if (i < right) Quick_Sort(sort, i, right);
            }  
    

    然后定义一个MinKMethod的方法来获取所需元素:

            public static void MinKMethod(int[] sort, int k)
            {
                Quick_Sort(sort, 0, sort.Length - 1);
                if (k > sort.Length)
                {
                    for (int j = 0; j < sort.Length; j++)
                    {
                        Console.Write(sort[j] + " ");
                    }
                    Console.WriteLine();
                }
                if (k <= 0)
                {
                    Console.WriteLine("Nothing Output");
                }
                if (k > 0 && k < sort.Length)
                {
                    for (int j = 0; j < k; j++)
                    {
                        Console.Write(sort[j] + " ");
                    }
                }
    
            } 
    

    这么做的话,最快需要O(NlogN)的时间进行排序,然后在O(1)的时间内将k个数取出。

    接下来看看如何用堆完成这个题:

            public static void FindKMin(int[] sort, int k)
            {
                int[] heap = sort;
                int rootIndex = k / 2 - 1;
                while (rootIndex >= 0)
                {
                    reheap(heap, rootIndex, k - 1);
                    rootIndex--;
                }
    
                for (int i = k, len=heap.Length; i < len; i++)
                {
                    if (heap[i]<heap[0])
                    {
                        heap[0] = heap[i];
                        reheap(heap, 0, k - 1);
                    }
                }
    
                Console.WriteLine("The {0} min element =",k);
                for (int i = 0; i < k; i++)
                {
                    Console.Write(heap[i] + " ");
                }
            }
    
            private static void reheap(int[] heap, int rootIndex, int lastInddex)
            {
                int orphan = heap[rootIndex];
                bool done = false;
                int leftIndex = rootIndex * 2 + 1;
                while (!done && leftIndex <= lastInddex)
                {
                    int largerIndex = leftIndex;
                    if (leftIndex+1 <= lastInddex)
                    {
                        int rightIndex = leftIndex + 1;
                        if (heap[rightIndex] > heap[leftIndex])
                        {
                            largerIndex = rightIndex;
                        }
                    }
    
                    if (orphan < heap[largerIndex])
                    {
                        heap[rootIndex] = heap[largerIndex];
                        rootIndex = largerIndex;
                        leftIndex = rootIndex * 2 + 1;
                    }
                    else
                    {
                        done = true;
                    }
                }
    
                heap[rootIndex] = orphan;
            }
    

    用堆解决这个问题其实思路并不难,前提是,需要对堆有一定的理解。

    作者:Ribbon 出处: http://www.cnblogs.com/Ribbon/ 本文版权归作者和博客园共有,欢迎转载。未经作者同意下,必须在文章页面明显标出原文链接及作者,否则保留追究法律责任的权利。 如果您认为这篇文章还不错或者有所收获,可以点击右下角的【推荐】按钮,因为你的支持是我继续写作,分享的最大动力!
  • 相关阅读:
    前端学习(1)~html标签讲解(一)
    前端学习(0)~vscode工具使用
    微服务之部署
    分解单块系统
    c#之线程基础(一)
    如何在windows 7 上使用docker
    CodeForces 995B Suit and Tie(贪心,暴力)
    CodeForces 993B Open Communication(STL 模拟)
    CodeForces 993A Two Squares(数学 几何)
    CodeForces 996B World Cup(思维)
  • 原文地址:https://www.cnblogs.com/Ribbon/p/3629676.html
Copyright © 2020-2023  润新知