码迷,mamicode.com
首页 > 其他好文 > 详细

网易2016笔试(3)

时间:2016-08-01 21:22:33      阅读:183      评论:0      收藏:0      [点我收藏+]

标签:

有一个整数数组,请你根据快速排序的思路,找出数组中第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);
        }
    }
      这样的话复杂度肯定降低,因为只用递归调用一边,否则要完成排序需要调用两边。虽然浪费了很长时间,但找到了问题的关键我还是很开心的。

网易2016笔试(3)

标签:

原文地址:http://blog.csdn.net/yutianxin123/article/details/52088331

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!