常考数据结构与算法:查找第K大元素算法

题目描述

有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数。

给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的数,保证答案存在。

扩展思考:如何处理数组中的重复元素?比如,对于数组a={1,3,5,2,2},第四大的元素应该是2还是1呢?

本文作这种分类:

如果第四大的元素是2,说明在处理第k大的元素时不处理重复的数据,也就是将原数组进行降序排序后,下标为k-1的元素。这种处理方法称之为“不处理重复数据方法”;

如果第四大的元素是1,说明已经忽略重复的数据了,这时候需要首先对a进行去重处理(可以用哈希表),然后再进行讨论。这种处理方法称之为“去除重复数据方法”。

下面的方法都默认为第一种。

分治法

快速排序使用了分治法的策略。它的基本思想是,选择一个基准数(一般称之为枢纽元),通过一趟排序将要排序的数据分割成独立的两部分:在枢纽元左边的所有元素都不比它大,右边所有元素都比它大,此时枢纽元就处在它应该在的正确位置上了。

在本问题中,假设有N个数存储在数组a中。我们从a中随机找出一个元素作为枢纽元,把数组分为两部分。其中左边元素都不比枢纽元大,右边元素都不比枢纽元小。此时枢纽元所在的位置记为mid。

如果右半边(包括a[mid])的长度恰好为k,说明a[mid]就是需要的第k大元素,直接返回a[mid]。

如果右半边(包括a[mid])的长度大于k,说明要寻找的第k大元素就在右半边,往右半边寻找。

如果右半边(包括a[mid])的长度小于k,说明要寻找的第k大元素就在左半边,往左半边寻找。

public class FindKth {
        public static void main(String[] args) {
            // [1,3,5,2,2],5,3
            int arr[] = {1,3,5,2,2};
            datastructure.FindKth f = new datastructure.FindKth();
            int result = f.findKth(arr, 5, 1);
            System.out.println(result);

            for(int t : arr){
                System.out.print(t+" ");
            }
            System.out.println("");
        }

        public int findKth(int[] a, int n, int k) {
            return find(a, 0,n-1, k);
        }

        public int find(int[] a, int start, int end, int k){

            // 比第一个元素大的放左边,小的放右边
            int p = partition(a, start, end);

            if(p+1 < k){
                return find(a, p+1,end, k);
            }

            if(p+1 > k){
                return find(a, start, p-1, k);
            }

            return a[p];
        }

        public int partition(int[] a, int start, int end){

            int i = start;
            int j = end + 1;
            int V = a[start];

            while(true){
                while(a[++i] > V){ // 直到比V小
                    if(i>=end) break;
                }

                while(a[--j] < V){// 直到比V大
                    if(j<=start) break;
                }

                if(i >= j)break;

                // 交换i,j位置的值
                exchange(a,i,j);
            }

            exchange(a,start,j);

            return j;
        }

        private void exchange(int[] a, int i, int j) {
            int temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
}

猜你喜欢

转载自blog.csdn.net/m0_37564426/article/details/114027932
今日推荐