2102-序列顺序查询

Raphael Liu Lv10

一个观光景点由它的名字 name 和景点评分 score 组成,其中 name 是所有观光景点中 唯一 的字符串,score
是一个整数。景点按照最好到最坏排序。景点评分 越高 ,这个景点越好。如果有两个景点的评分一样,那么 字典序较小 的景点更好。

你需要搭建一个系统,查询景点的排名。初始时系统里没有任何景点。这个系统支持:

  • 添加 景点,每次添加 一个 景点。
  • 查询 已经添加景点中第 i 的景点,其中 i 是系统目前位置查询的次数(包括当前这一次)。
    • 比方说,如果系统正在进行第 4 次查询,那么需要返回所有已经添加景点中第 4 好的。

注意,测试数据保证 任意查询时刻 ,查询次数都 不超过 系统中景点的数目。

请你实现 SORTracker 类:

  • SORTracker() 初始化系统。
  • void add(string name, int score) 向系统中添加一个名为 name 评分为 score 的景点。
  • string get() 查询第 i 好的景点,其中 i 是目前系统查询的次数(包括当前这次查询)。

示例:

**输入:**
["SORTracker", "add", "add", "get", "add", "get", "add", "get", "add", "get", "add", "get", "get"]
[[], ["bradford", 2], ["branford", 3], [], ["alps", 2], [], ["orland", 2], [], ["orlando", 3], [], ["alpine", 2], [], []]
**输出:**
[null, null, null, "branford", null, "alps", null, "bradford", null, "bradford", null, "bradford", "orland"]

**解释:**
SORTracker tracker = new SORTracker(); // 初始化系统
tracker.add("bradford", 2); // 添加 name="bradford" 且 score=2 的景点。
tracker.add("branford", 3); // 添加 name="branford" 且 score=3 的景点。
tracker.get();              // 从好带坏的景点为:branford ,bradford 。
                            // 注意到 branford 比 bradford 好,因为它的 **评分更高** (3 > 2) 。
                            // 这是第 1 次调用 get() ,所以返回最好的景点:"branford" 。
tracker.add("alps", 2);     // 添加 name="alps" 且 score=2 的景点。
tracker.get();              // 从好到坏的景点为:branford, alps, bradford 。
                            // 注意 alps 比 bradford 好,虽然它们评分相同,都为 2 。
                            // 这是因为 "alps" **字典序**  比 "bradford" 小。
                            // 返回第 2 好的地点 "alps" ,因为当前为第 2 次调用 get() 。
tracker.add("orland", 2);   // 添加 name="orland" 且 score=2 的景点。
tracker.get();              // 从好到坏的景点为:branford, alps, bradford, orland 。
                            // 返回 "bradford" ,因为当前为第 3 次调用 get() 。
tracker.add("orlando", 3);  // 添加 name="orlando" 且 score=3 的景点。
tracker.get();              // 从好到坏的景点为:branford, orlando, alps, bradford, orland 。
                            // 返回 "bradford".
tracker.add("alpine", 2);   // 添加 name="alpine" 且 score=2 的景点。
tracker.get();              // 从好到坏的景点为:branford, orlando, alpine, alps, bradford, orland 。
                            // 返回 "bradford" 。
tracker.get();              // 从好到坏的景点为:branford, orlando, alpine, alps, bradford, orland 。
                            // 返回 "orland" 。

提示:

  • name 只包含小写英文字母,且每个景点名字互不相同。
  • 1 <= name.length <= 10
  • 1 <= score <= 105
  • 任意时刻,调用 get 的次数都不超过调用 add 的次数。
  • 总共 调用 addget 不超过 4 * 104

为了高效插入数据,我们可以用平衡树来维护所有景点。

注意到每次 get 后仅会将查询次数加一,我们可以用一个迭代器(指针)cur 指向查询需要返回的元素,这样对于查询操作,每次查询结束后将 cur 移至其下一个元素。

对于添加操作,如果添加的景点排在 cur 前面,那么为了保证 cur 仍然指向第 i 好的景点,我们将 cur 移至其前一个元素,否则不移动 cur。

代码实现时,可以在初始化时插入一个哨兵元素,从而简化判断逻辑。

[sol1-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class SORTracker {
set<pair<int, string>> s;
set<pair<int, string>>::iterator cur;

public:
SORTracker() {
s.emplace(0, ""); // 哨兵
cur = s.begin();
}

void add(string name, int score) {
pair<int, string> p = {-score, name};
s.emplace(p);
if (p < *cur) --cur;
}

string get() {
return cur++->second;
}
};
[sol1-Go]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
type pair struct {
score int
name string
}

func compare(x, y interface{}) int {
a, b := x.(pair), y.(pair)
if a.score > b.score || a.score == b.score && a.name < b.name {
return -1
}
return 1
}

type SORTracker struct {
*redblacktree.Tree
cur redblacktree.Iterator
}

func Constructor() SORTracker {
root := redblacktree.NewWith(compare)
root.Put(pair{}, nil) // 哨兵
return SORTracker{root, root.IteratorAt(root.Left())}
}

func (t *SORTracker) Add(name string, score int) {
p := pair{score, name}
t.Put(p, nil)
if compare(p, t.cur.Key()) < 0 {
t.cur.Prev() // 移动至前一个元素
}
}

func (t *SORTracker) Get() string {
name := t.cur.Key().(pair).name
t.cur.Next() // 移动至下一个元素
return name
}

Python 用户可以直接用 SortedList 模拟。

[sol2-Python3]
1
2
3
4
5
6
7
8
9
10
11
12
13
from sortedcontainers import SortedList

class SORTracker:
def __init__(self):
self.d = SortedList()
self.i = 0

def add(self, name: str, score: int) -> None:
self.d.add((-score, name))

def get(self) -> str:
self.i += 1
return self.d[self.i - 1][1]
 Comments
On this page
2102-序列顺序查询