程序员面试金典 10.10

Rank from Stream:设计一个在线算法,包含track()getRankOfNumber()两个方法。track(int x)读取输入中的整数并存储,getRankOfNumber(int x)返回已经读取的不大于x的整数数量。

最先想到的方法就是把读取的数据按序存入数组中:

  • track()的逻辑就是找到第1个比x大的数,然后将这个数以及后面的数向后移动,并将x插入
  • getRankOfNumber()的逻辑就是找到第1个比x大的数,然后返回x的下标就可以了(注意书上要求当x数存在的多个时,返回的结果不应该包含x本身的计数,也就是返回最后一个x的下标)
class StreamRank {
private:
    vector<int> vec;
    size_t binarySearch(const int x)
    {
        size_t begin = 0, end = vec.size();
        while(begin < end){
            size_t mid = begin + (end - begin) / 2;
            if(vec[mid] <= x) begin = mid + 1;
            else end = mid;
        }
        return begin;
    }
public:
    StreamRank() {

    }
    
    void track(int x) {
        size_t pos = binarySearch(x);
        vec.push_back(0);
        for(size_t i = vec.size(); i > pos && i > 1; i--)
        {
            vec[i - 1] = vec[i - 2];
        }
        vec[pos] = x;
    }
    
    int getRankOfNumber(int x) {
        return binarySearch(x);
    }
};

/**
 * Your StreamRank object will be instantiated and called as such:
 * StreamRank* obj = new StreamRank();
 * obj->track(x);
 * int param_2 = obj->getRankOfNumber(x);
 */

由于上一题的下标,我一度以为二分法查找第一个大于目标值的数都不会写了。采用顺序存储时,两种算法的复杂度都可以达到O(logn),但是track()需要批量移动元素。

为了避免这一点,可以选择采用二叉搜索树的形式,其中每个节点包含子节点指针,左子树大小leftSubSize和重复次数dup,这样在查找的过程中,累加leftSubSizedup即可。

class StreamRank {
private:
    struct Node
    {
        int value, leftSubSize, dup;
        Node* left;
        Node*right;
        Node(int value) : value(value), leftSubSize(0), dup(1), left(nullptr), right(nullptr){};
    };
    Node* root;
public:
    StreamRank() {
        root = nullptr;
    }
    
    void track(int x) {
        Node** curr = &root;
        while(*curr != nullptr){
            if(x < (*curr)->value){
                (*curr)->leftSubSize++;
                curr = &(*curr)->left;
            }
            else if(x > (*curr)->value){
                curr = &(*curr)->right;
            }
            else{
                (*curr)->dup++;
                return;
            }
        }
        *curr = new Node(x);
        return;
    }
    
    int getRankOfNumber(int x) {
        Node** curr = &root;
        int ret = 0;
        while(*curr != nullptr){
            if(x < (*curr)->value){
                curr = &(*curr)->left;
            }
            else if(x > (*curr)->value){
                ret += (*curr)->leftSubSize + (*curr)->dup;
                curr = &(*curr)->right;
            }
            else{
                ret += (*curr)->leftSubSize + (*curr)->dup;
                return ret;
            }
        }
        return ret;
    }
};

/**
 * Your StreamRank object will be instantiated and called as such:
 * StreamRank* obj = new StreamRank();
 * obj->track(x);
 * int param_2 = obj->getRankOfNumber(x);
 */

你可能感兴趣的:(《程序员面试金典》)