Skip to content

feat: add solutions to lc problem: No.2102 #2776

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 183 additions & 0 deletions solution/2100-2199/2102.Sequentially Ordinal Rank Tracker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,187 @@ tracker.get(); // 从好到坏的景点为:branford, orlando, alp

## 解法

### 方法一:有序集合

我们可以使用有序集合来存储景点,用一个变量 $i$ 来记录当前查询的次数,初始时 $i = -1$。

调用 `add` 方法时,我们将景点的评分取负数,这样就可以使用有序集合按照评分从大到小排序,如果评分相同,按照景点名字的字典序从小到大排序。

调用 `get` 方法时,我们将 $i$ 加一,然后返回有序集合中第 $i$ 个景点的名字。

每次操作的时间复杂度为 $O(\log n)$,其中 $n$ 为已添加的景点数。空间复杂度为 $O(n)$。

<!-- tabs:start -->

```python
from sortedcontainers import SortedList


class SORTracker:

def __init__(self):
self.sl = SortedList()
self.i = -1

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

def get(self) -> str:
self.i += 1
return self.sl[self.i][1]


# Your SORTracker object will be instantiated and called as such:
# obj = SORTracker()
# obj.add(name,score)
# param_2 = obj.get()
```

```cpp
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;

template <class T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

class SORTracker {
public:
SORTracker() {
}

void add(string name, int score) {
st.insert({-score, name});
}

string get() {
return st.find_by_order(++i)->second;
}

private:
ordered_set<pair<int, string>> st;
int i = -1;
};

/**
* Your SORTracker object will be instantiated and called as such:
* SORTracker* obj = new SORTracker();
* obj->add(name,score);
* string param_2 = obj->get();
*/
```

<!-- tabs:end -->

### 方法二:双优先队列(大小根堆)

我们注意到,由于本题中的查询操作是按照严格递增的顺序进行的,因此我们可以使用类似于数据流中的中位数的方法,定义两个优先队列 `good` 和 `bad`,其中 `good` 是一个小根堆,存储当前最好的景点,`bad` 是一个大根堆,存储当前第 $i$ 好的景点。

每次调用 `add` 方法时,我们将景点的评分和名字加入 `good` 中,然后将 `good` 中的最差的景点加入 `bad` 中。

每次调用 `get` 方法时,我们将 `bad` 中的最好的景点加入 `good` 中,然后返回 `good` 中的最差的景点。

每次操作的时间复杂度为 $O(\log n)$,其中 $n$ 为已添加的景点数。空间复杂度为 $O(n)$。

<!-- tabs:start -->

```python
class Node:
def __init__(self, s: str):
self.s = s

def __lt__(self, other):
return self.s > other.s


class SORTracker:

def __init__(self):
self.good = []
self.bad = []

def add(self, name: str, score: int) -> None:
score, node = heappushpop(self.good, (score, Node(name)))
heappush(self.bad, (-score, node.s))

def get(self) -> str:
score, name = heappop(self.bad)
heappush(self.good, (-score, Node(name)))
return self.good[0][1].s


# Your SORTracker object will be instantiated and called as such:
# obj = SORTracker()
# obj.add(name,score)
# param_2 = obj.get()
```

```java
class SORTracker {
private PriorityQueue<Map.Entry<Integer, String>> good = new PriorityQueue<>(
(a, b)
-> a.getKey().equals(b.getKey()) ? b.getValue().compareTo(a.getValue())
: a.getKey() - b.getKey());
private PriorityQueue<Map.Entry<Integer, String>> bad = new PriorityQueue<>(
(a, b)
-> a.getKey().equals(b.getKey()) ? a.getValue().compareTo(b.getValue())
: b.getKey() - a.getKey());

public SORTracker() {
}

public void add(String name, int score) {
good.offer(Map.entry(score, name));
bad.offer(good.poll());
}

public String get() {
good.offer(bad.poll());
return good.peek().getValue();
}
}

/**
* Your SORTracker object will be instantiated and called as such:
* SORTracker obj = new SORTracker();
* obj.add(name,score);
* String param_2 = obj.get();
*/
```

```cpp
using pis = pair<int, string>;

class SORTracker {
public:
SORTracker() {
}

void add(string name, int score) {
good.push({-score, name});
bad.push(good.top());
good.pop();
}

string get() {
good.push(bad.top());
bad.pop();
return good.top().second;
}

private:
priority_queue<pis, vector<pis>, less<pis>> good;
priority_queue<pis, vector<pis>, greater<pis>> bad;
};

/**
* Your SORTracker object will be instantiated and called as such:
* SORTracker* obj = new SORTracker();
* obj->add(name,score);
* string param_2 = obj->get();
*/
```

<!-- tabs:end -->

<!-- end -->
183 changes: 183 additions & 0 deletions solution/2100-2199/2102.Sequentially Ordinal Rank Tracker/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,187 @@ tracker.get(); // Sorted locations: branford, orlando, alpine, alps

## Solutions

### Solution 1: Ordered Set

We can use an ordered set to store the attractions, and a variable $i$ to record the current number of queries, initially $i = -1$.

When calling the `add` method, we take the negative of the attraction's rating, so that we can use the ordered set to sort by rating in descending order. If the ratings are the same, sort by the dictionary order of the attraction names in ascending order.

When calling the `get` method, we increment $i$ by one, and then return the name of the $i$-th attraction in the ordered set.

The time complexity of each operation is $O(\log n)$, where $n$ is the number of added attractions. The space complexity is $O(n)$.

<!-- tabs:start -->

```python
from sortedcontainers import SortedList


class SORTracker:

def __init__(self):
self.sl = SortedList()
self.i = -1

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

def get(self) -> str:
self.i += 1
return self.sl[self.i][1]


# Your SORTracker object will be instantiated and called as such:
# obj = SORTracker()
# obj.add(name,score)
# param_2 = obj.get()
```

```cpp
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;

template <class T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

class SORTracker {
public:
SORTracker() {
}

void add(string name, int score) {
st.insert({-score, name});
}

string get() {
return st.find_by_order(++i)->second;
}

private:
ordered_set<pair<int, string>> st;
int i = -1;
};

/**
* Your SORTracker object will be instantiated and called as such:
* SORTracker* obj = new SORTracker();
* obj->add(name,score);
* string param_2 = obj->get();
*/
```

<!-- tabs:end -->

### Solution 2: Double Priority Queue (Min-Max Heap)

We notice that the query operations in this problem are performed in strictly increasing order. Therefore, we can use a method similar to the median in the data stream. We define two priority queues `good` and `bad`. `good` is a min-heap, storing the current best attractions, and `bad` is a max-heap, storing the current $i$-th best attraction.

Each time the `add` method is called, we add the attraction's rating and name to `good`, and then add the worst attraction in `good` to `bad`.

Each time the `get` method is called, we add the best attraction in `bad` to `good`, and then return the worst attraction in `good`.

The time complexity of each operation is $O(\log n)$, where $n$ is the number of added attractions. The space complexity is $O(n)$.

<!-- tabs:start -->

```python
class Node:
def __init__(self, s: str):
self.s = s

def __lt__(self, other):
return self.s > other.s


class SORTracker:

def __init__(self):
self.good = []
self.bad = []

def add(self, name: str, score: int) -> None:
score, node = heappushpop(self.good, (score, Node(name)))
heappush(self.bad, (-score, node.s))

def get(self) -> str:
score, name = heappop(self.bad)
heappush(self.good, (-score, Node(name)))
return self.good[0][1].s


# Your SORTracker object will be instantiated and called as such:
# obj = SORTracker()
# obj.add(name,score)
# param_2 = obj.get()
```

```java
class SORTracker {
private PriorityQueue<Map.Entry<Integer, String>> good = new PriorityQueue<>(
(a, b)
-> a.getKey().equals(b.getKey()) ? b.getValue().compareTo(a.getValue())
: a.getKey() - b.getKey());
private PriorityQueue<Map.Entry<Integer, String>> bad = new PriorityQueue<>(
(a, b)
-> a.getKey().equals(b.getKey()) ? a.getValue().compareTo(b.getValue())
: b.getKey() - a.getKey());

public SORTracker() {
}

public void add(String name, int score) {
good.offer(Map.entry(score, name));
bad.offer(good.poll());
}

public String get() {
good.offer(bad.poll());
return good.peek().getValue();
}
}

/**
* Your SORTracker object will be instantiated and called as such:
* SORTracker obj = new SORTracker();
* obj.add(name,score);
* String param_2 = obj.get();
*/
```

```cpp
using pis = pair<int, string>;

class SORTracker {
public:
SORTracker() {
}

void add(string name, int score) {
good.push({-score, name});
bad.push(good.top());
good.pop();
}

string get() {
good.push(bad.top());
bad.pop();
return good.top().second;
}

private:
priority_queue<pis, vector<pis>, less<pis>> good;
priority_queue<pis, vector<pis>, greater<pis>> bad;
};

/**
* Your SORTracker object will be instantiated and called as such:
* SORTracker* obj = new SORTracker();
* obj->add(name,score);
* string param_2 = obj->get();
*/
```

<!-- tabs:end -->

<!-- end -->
Loading