剑指offer 最小的k个数 、 leetcode 215. Kth Largest Element in an Array 、lintcode 80. Median、295. Find Median from Data Stream(剑指 数据流中位数) topK

 

 

注意multiset的一个bug:

multiset带一个参数的erase函数原型有两种。一是传递一个元素值,如上面例子代码中,这时候删除的是集合中所有值等于输入值的元素,并且返回删除的元素个数;另外一种是传递一个指向某个元素的iterator,这时候删除的就是这个对应的元素,无返回值。

https://www.cnblogs.com/lakeone/p/5600494.html

删除的时候一定不能删除指针,只能删除迭代器

leetcode那个题就是在这个地方出错的:

Input: [3,2,3,1,2,4,5,5,6,7,7,8,2,3,1,1,1,10,11,5,6,2,4,7,8,5,6] 20
Output: 3

Expected: 2

如果container.erase(*con),最后小根堆的大小就只有19个

container.erase(con)才是正确的

 

剑指offer 最小的k个数:

 这是partition版本的

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> result;
        int length = input.size();
        if(input.empty() || length <= 0 || k <= 0 || length < k)
            return result;
        int start = 0;
        int end = length - 1;
        int index = partition(input,start,end);
        while(index != k-1){
            if(index > k-1){
                end = index - 1;
                index = partition(input,start,end);
            }
            else{
                start = index + 1;
                index = partition(input,start,end);
            }
        }
        for(int i = 0;i < k;i++)
            result.push_back(input[i]);
        return result;
    }
    int partition(vector<int> &input,int start,int end){
        int small = start - 1;
        for(int i = start;i < end;i++){
            if(input[i] < input[end]){
                small++;
                if(small != i)
                    swap(input,small,i);
            }
        }
        small++;
        swap(input,small,end);
        return small;
    } 
    void swap(vector<int>& input,int a,int b){
        int tmp = input[a];
        input[a] = input[b];
        input[b] = tmp;
    }
};

 这是基于大根堆的:

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> output;
        int length = input.size();
        if(input.empty() || k <= 0 || length < k)
            return output;
        multiset<int,greater<int>> numbers;
        multiset<int,greater<int>>::iterator greaternumber;
        
        vector<int>::iterator iter = input.begin();
        for(;iter != input.end();iter++){
            if(numbers.size() < k)
                numbers.insert(*iter);
            else{
                greaternumber = numbers.begin();
                if(*greaternumber > *iter){
                    numbers.erase(*greaternumber);
                    numbers.insert(*iter);
                }
            }
        }
        for(greaternumber = numbers.begin();greaternumber != numbers.end();greaternumber++){
            output.push_back(*greaternumber);
        }
        return output;
    }
};

 

 

leetcode 215. Kth Largest Element in an Array

使用小根堆

错误写法:

在这个情况:{3,2,3,1,2,4,5,5,6,7,7,8,2,3,1,1,1,10,11,5,6,2,4,7,8,5,6},会报错

错误在container.erase(*con),正确应该是container.erase(con)。erase(*con)删除的是数值,比如top是3,会把container里面所有的3都删除掉 ,erase(con)删除的是指针,只删除top的这个值

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        multiset<int,less<int>> container;
        multiset<int,less<int>>::iterator con;

        for(int i = 0;i < nums.size();i++){
            if(container.size() < k)
                container.insert(nums[i]);
            else{
                con = container.begin();
                if(*con < nums[i]){
                    container.erase(*con);
                    container.insert(nums[i]);
                }
            }
        }
        con = container.begin();
        return *con;
    }
};

正确写法:

可以写

if(length <= 0 || k <= 0 || length < k)
  return -1;

针对这个判断条件,有可能输入的不全是正数,返回-1就有问题,原题目中其实是排除了这些边界条件的

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        multiset<int,less<int>> container;
        multiset<int,less<int>>::iterator con;
        //if(length <= 0 || k <= 0 || length < k)
            //return -1;
        for(int i = 0;i < nums.size();i++){
            if(container.size() < k)
                container.insert(nums[i]);
            else{
                con = container.begin();
                if(*con < nums[i]){
                    container.erase(con);
                    container.insert(nums[i]);
                }
            }
        }
        con = container.begin();
        return *con;
    }
};

 

自己写的一个最新的实现:

以后直接统一使用prority_queue好了,方便记忆。greater是小根堆,可以这样记忆,prority_queue里面的compare函数是比较两个value大小的排序方式,greater就是更大的排后面,更小的排前面,即升序队列,所以就是小根堆。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        std::priority_queue<int, vector<int>, greater<int>> container;
        for (int i = 0; i < nums.size(); i++) {
            if (i < k) {
                container.push(nums[i]);
            } else {
                const int min_num = container.top();
                if (nums[i] > min_num) {
                    container.pop();
                    container.push(nums[i]);
                }
            }
        }
        return container.top();
    }
};

 

 

使用partition的方式:

注意这里要增加end = index - 1和start = index + 1,因为这里不是递归,是使用的循环。如果你直接把end换成index - 1带入patition函数,对于之后的partition函数,这个end实际上还是没变的。

没有真正达到所以1/2的目的。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        int n = nums.size();
        k = n - k;
        int start = 0,end = nums.size() - 1;
        int index = partition(nums,start,end);
        int freq = 0;
        while(index != k){
            if(index > k){
                end = index - 1;
                index = partition(nums,start,end);
            }
            else{
                start = index + 1;
                index = partition(nums,start,end);
            }
        }
           return nums[index];
    }
    int partition(vector<int>& nums,int start,int end){
        int index = start - 1;
        for(int i = start;i < end;i++){
            if(nums[i] < nums[end]){
                index++;
                if(index != i)
                    swap(nums[index],nums[i]);
            }
        }
        index++;
        swap(nums[index],nums[end]);
        return index;
    }
};

 

 

80. Median

这个题是在无序数组中找经过排序后的中间位置的值。实际上这个题和Kth Largest Element in an Array差不多,Kth Largest Element in an Array是求第k大,这个题是限定了k是中间位置,并且要求时间复杂度是O(n),所以使用partition的方式就可以。

时间复杂度分析:

https://rcoh.me/posts/linear-time-median-finding/

这是平局时间复杂度

实际上就是O(N) + O(N/2) + O(N/4) + O(N/8)....,使用等比数列求和公式:

就可以得到是一个O(2N)的复杂度,即O(N)

 

class Solution {
public:
    /**
     * @param nums: A list of integers
     * @return: An integer denotes the middle number of the array
     */
    int median(vector<int> &nums) {
        // write your code here
        int start = 0,end = nums.size() - 1;
        int index = partition(nums,start,end);
        int k = (nums.size() - 1)/2;
        while(k != index){
            if(index < k){
                start = index + 1;
                index = partition(nums,start,end);
            }
            else{
                end = index - 1;
                index = partition(nums,start,end);
            }
        }
        return nums[index];
    }
    int partition(vector<int>& nums,int start,int end){
        int index = start - 1;
        for(int i = start;i < end;i++){
            if(nums[i] < nums[end]){
                index++;
                if(i != index)
                    swap(nums[i],nums[index]);
            }
        }
        index++;
        swap(nums[end],nums[index]);
        return index;
    }
};

 

 

 

295. Find Median from Data Stream

使用两个堆进行存储,一个是大根堆,即存储所有较小的数;一个是小根堆,即存储所有较大的数。使用priority_queue来代表大小根堆。

class MedianFinder {
public:
    /** initialize your data structure here. */
    MedianFinder() {
        
    }
    
    void addNum(int num) {
        if(p.size() == 0 || p.top() > num)
            p.push(num);
        else
            q.push(num);
        if(p.size() > q.size() + 1){
            int tmp = p.top();
            p.pop();
            q.push(tmp);
        }
        if(q.size() > p.size()){
            int tmp = q.top();
            q.pop();
            p.push(tmp);
        }
    }
    
    double findMedian() {
        return p.size() > q.size() ? p.top() * 1.0 : (p.top() + q.top())/2.0;
    }
    priority_queue<int,vector<int>,less<int>> p;
    priority_queue<int,vector<int>,greater<int>> q;
};

 

posted @ 2018-09-14 09:37  有梦就要去实现他  阅读(179)  评论(0编辑  收藏  举报