[CareerCup] 11.8 The Rank of Number 數的排行
11.8 Imagine you are reading in a stream of integers. Periodically, you wish to be able to look up the rank of a number x (the number of values less than or equal tox). Implement the data structures and algorithms to support these operations.That is, implement the method track(int x), which is called when each number is generated, and the method getRankOfNumber(int x), which returns the number of values less than or equal to x (not including x itself).
EXAMPLE
Stream (in order of appearance): 5, 1, 4, 4, 5, 9, 7, 13, 3
getRankOfNumber(l) = 0
getRankOfNumber(3) = 1
getRankOfNumber(4) = 3
這道題給了我們一個無序陣列,讓我們求每個數字的排行,排行為幾就表示有幾個小於或等於該數字的數。我們首先需要用一個數據結構來儲存有序陣列,用向量的話加數字不高效,用priority_queue或者multiset的話求rank又太麻煩,引文不能直接通過座標訪問元素。那麼我們考慮用另一種有序的資料結構,二叉搜尋樹Binary Search Tree,我們知道BST的性質是左<=中<右,中序遍歷一個BST的結果就是有序陣列。為了更有效的找出rank,我們在加入新數字的時候,記錄一個變數left_size,表示此數字的左子樹的節點數。我們來看下面這個例子,每個節點表示當前數字,括號中的數字表示當前節點的左子節點的個數。
20(4) / \ / \ 15(3) 25(2) / / / / 10(1) 23(0) / \ \ / \ \ 5(0) 13(0) 24(0)
假如我們要找24的rank,我們將24與根節點20相比較,發現24應該在根節點的右邊,根節點的左子樹有四個節點,加上根節點本身,我們現已知有5個小於24的數,將counter設為5,然後我們再跟25比,發現24在其左側,不更新counter,然後和23比,24在其右側,counter加1,因為23沒有左子樹,最後我們就可知24的rank為6, 參見程式碼如下:
class RankNode { public: int left_size = 0; RankNode *left; RankNode *right; int data = 0; RankNode(int d): data(d), left(nullptr), right(nullptr) {} void insert(int d) { if (d <= data) { if (left != nullptr) left->insert(d); else left = new RankNode(d); ++left_size; } else { if (right != nullptr) right->insert(d); else right = new RankNode(d); } } int getRank(int d) { if (d == data) return left_size; else if (d < data) { return left == nullptr ? -1 : left->getRank(d); } else { return right == nullptr ? -1 : right->getRank(d) + 1 + left_size; } } }; class Solution { public: RankNode *root; void track(int number) { if (root == nullptr) { root = new RankNode(number); } else { root->insert(number); } } int getRankOfNumber(int number) { return root->getRank(number); } };