求最小的K个数 ,第K大的数

题目描述

思路1 使用长度为K的最大堆

举例说明

  • [4 5 1 6_max]
  • push(2) [2,4, 5 1 6_max] pop(6_max)
  • get [2,1,4,5]

C++ 代码

  • 也可以使用make_heap 算法
class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        //   如果用最大堆  [4 5  1 6_max] 
        //   push(2) 【2,4, 5 1 6_max】 pop(6_max)
            // [2,1,4,5]
        std::priority_queue<int  > priorityA;
        for(int i=0;i<k;i++)
        {
            priorityA.push(arr[i]);
        }

        for(int i=k;i<arr.size();i++)
        {
            priorityA.push(arr[i]);
            priorityA.pop();
        }

        std::vector<int> res;
        while(!priorityA.empty())
        {
            res.push_back(priorityA.top());
            priorityA.pop();
        }

        return res;

    }
};

思路2 使用快排中的portion 即分治

  • 给定pivot 确保左小右大
  • 返回给定pivot在新序列中的位置 ( retIdx)
  • when retIdx < k 说明[...retIdx,retIdx+1,...k ,k+1...]
    portion(pivot= arr[retIdx+1],left=retIdx+1,right= arr.size()-1)
    when retIdx> k 说明[...,k-1,k,...retIdx-1,retIdx,...arr.size]
    portion(pivot= arr[retIdx-1],left=0,right=retIdx-1)
    when retIdx=k ,return arr[0,retIdx]

调试用的代码

class Solution {
public:

    int myPortion(vector<int>& arr, int left,int right)
    {
        int pivot= arr[left];
        int aI=left,bI=right;
        // [3,5,4,1,9]
        // [3,1,4,5,9] 
        while(aI<=bI)
        {
            //左边 找到第一个大于pivot的
            while(aI<=bI && arr[aI] <= pivot )
            {
                aI ++;
            }

            //右边 逆向寻找 找到一个小于pivot
            while(aI<=bI && arr[bI] >= pivot)
            {
                bI--;
            }
           std::swap(arr[aI], arr[bI]);
        }
         std::swap(arr[aI], arr[left]);
      
         for(auto x: arr) std::cout << x << " ";
         std::cout << std::endl;
         return aI;
    }


    vector<int> getLeastNumbers(vector<int>& arr, int k) {
    //   利用qsort portion 
    //   给定axis 确保左小右大 
    //   返回axis在新序列中的位置 is retIdx
    //   when retIdx < k   说明[...retIdx,retIdx+1,...k ,k+1...]
    //     portion(arr[retIdx+1],left=retIdx+1,right= arr.size()-1)
    //   when retIdx> k  说明[...,k-1,k,...retIdx-1,retIdx,...arr.size] 
    //      portion(arr[retIdx-1],left=0,right=retIdx-1) 
    //   when retIdx=k ,return arr[0,retIdx]

         int retIdx = myPortion(arr,0, arr.size()-1);
         while( retIdx!=k )
         {
             if(retIdx<k )     retIdx= myPortion(arr,retIdx+1,arr.size()-1);
             else retIdx = myPortion(arr,0,  retIdx-1);
         }

         std::vector<int> res(arr.begin() ,arr.begin()+k);
         return res;
    }
};

采用递归优化后的代码

class Solution {
public:
int portion(std::vector<int>& arr,int left,int right)
{
    int pivotnum = arr[left];
	int i = left, j = right;
	while (i<j)
	{
		//j= less pivotnum ,from right
		while ( i<j && arr[j] >= pivotnum   )
		{
			j--;
		}
        //这里pivot =  arr[i] , 因有备份,可在这里赋值 
		arr[i] = arr[j];
		//i= greater than pivotnum ,from left
		while (i<j && arr[i] <= pivotnum)
		{
			i++;
		}
		arr[j] = arr[i];
	}
	arr[i] = pivotnum;

    //     for(auto x: arr) std::cout << x << " ";
    // std::cout << std::endl;
    
	return i;
}
 
int FindKth(std::vector<int>& arr,int left,int right,int k)
{
    int idx=portion(arr,left,right);
    if(idx>k)
    {
         return   FindKth(arr,left,idx-1,k);
    }else if(idx< k)
    {
        return    FindKth(arr,idx+1,right,k);
    }
    return arr[idx];
}

   

    vector<int> getLeastNumbers(vector<int>& arr, int k)
    {    if(k==0) return {};
        if(k==arr.size() ) return arr;
           vector<int>res;
           FindKth(arr,0,arr.size()-1,k); 
           for(int i=0;i<k;i++)
           {
               auto x=arr[i];
              // auto x=FindKth(arr,0,arr.size()-1,i);
              res.push_back(x);
           }
           return res;
    }
 
};
posted @ 2021-05-14 09:32  boyang987  阅读(38)  评论(0编辑  收藏  举报