网易2016笔试(3)

来源:互联网 发布:埃米特矩阵 编辑:程序博客网 时间:2024/05/16 18:10

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

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

测试样例:[1,3,5,2,2],5,3
返回:2

      我的第一个思路,使用快排进行排序,排序后就可以得到第k个最大的数了。
      
 int quicksort(vector<int>&a,int i,int j)        {        int k=a[i];        while(i<j)            {            while(j>i&&a[j]>=k)j--;            if(i<j)            {                a[i]=a[j];                i++;            }            while(i<j&&a[i]<=k)i++;            if(i<j)                {                a[j]=a[i];                j--;            }        }        a[i]=k;        return i;    }    int findKth(vector<int> a, int n, int K) {        // write code here        int m=quicksort(a,0,n-1);        quicksort(a,0,m-1);        quicksort(a,m+1,n-1);        return a[n-K];    }
      思路我觉得没问题,但总是得不到正确结果。而且例子给我的是49个数。没看出错误我就跟代码,第一步即刻发现我快排没排对啊。这样我就着重看快排。果然3个quicksort是什么鬼啊?应该是分治递归。这样代码改为如下即可。
      
 int quicksort(vector<int>&a,int i,int j)        {        int k=a[i];        while(i<j)            {            while(j>i&&a[j]>=k)j--;            if(i<j)            {                a[i]=a[j];                i++;            }            while(i<j&&a[i]<=k)i++;            if(i<j)                {                a[j]=a[i];                j--;            }        }        a[i]=k;        return i;    }        void quickMerge(vector<int>&A,int l,int j)        {        if(l<j)            {        int m=quicksort(A,l,j);        quickMerge(A,l,m-1);        quickMerge(A,m+1,j);        }             }    int findKth(vector<int> a, int n, int K) {        // write code here        quickMerge(a,0,n-1);        return a[n-K];    }
      这个复杂度当然是O(nlogn),但是在分治的基础上修改代码也可以采用如下方法。
      
 int findKth(vector<int> a, int n, int K) {        return quickfind(a, 0, n-1, K);    }          int quickfind(vector<int>& a, int left, int right, int k) {        int i = left;        int j = right;        int mark = a[left];                  while (i < j) {            while (i < j && a[j] >= mark)                --j;            if (i < j)                a[i++] = a[j];                          while (i < j && a[i] <= mark)                ++i;            if (i < j)                a[j--] = a[i];        }        a[i] = mark;                  //哨兵右侧比他大的数字个数        int big_num = right - i;                 //如果哨兵刚好是第K大的数        if (k - big_num - 1 == 0)            return mark;        else if (k - big_num - 1 > 0) {            //如果右侧数字个数不够K个,则从左侧找第k-big_num-1大的数            return quickfind(a, left, i - 1, k - big_num - 1);        } else {            //如果右侧数字个数比K多,则在右侧找第K大的数            return quickfind(a, i + 1, right, k);        }    }
      这样的话复杂度肯定降低,因为只用递归调用一边,否则要完成排序需要调用两边。虽然浪费了很长时间,但找到了问题的关键我还是很开心的。
0 0
原创粉丝点击