设计一个数字容器系统,可以实现以下功能:
- 在系统中给定下标处 插入 或者 替换 一个数字。
- 返回 系统中给定数字的最小下标。
请你实现一个 NumberContainers
类:
NumberContainers()
初始化数字容器系统。void change(int index, int number)
在下标index
处填入number
。如果该下标index
处已经有数字了,那么用number
替换该数字。int find(int number)
返回给定数字number
在系统中的最小下标。如果系统中没有number
,那么返回-1
。
示例:
输入: ["NumberContainers", "find", "change", "change", "change", "change", "find", "change", "find"] [[], [10], [2, 10], [1, 10], [3, 10], [5, 10], [10], [1, 20], [10]] 输出: [null, -1, null, null, null, null, 1, null, 2] 解释: NumberContainers nc = new NumberContainers(); nc.find(10); // 没有数字 10 ,所以返回 -1 。 nc.change(2, 10); // 容器中下标为 2 处填入数字 10 。 nc.change(1, 10); // 容器中下标为 1 处填入数字 10 。 nc.change(3, 10); // 容器中下标为 3 处填入数字 10 。 nc.change(5, 10); // 容器中下标为 5 处填入数字 10 。 nc.find(10); // 数字 10 所在的下标为 1 ,2 ,3 和 5 。因为最小下标为 1 ,所以返回 1 。 nc.change(1, 20); // 容器中下标为 1 处填入数字 20 。注意,下标 1 处之前为 10 ,现在被替换为 20 。 nc.find(10); // 数字 10 所在下标为 2 ,3 和 5 。最小下标为 2 ,所以返回 2 。
提示:
1 <= index, number <= 10^9
- 调用
change
和find
的 总次数 不超过10^5
次。
提示 1
Use a hash table to efficiently map each number to all of its indices in the container and to map each index to their current number.
提示 2
In addition, you can use ordered set to store all of the indices for each number to solve the find method. Do not forget to update the ordered set according to the change method.
解法1:平衡树(有序集合)
同类题型详解:LeetCode 2353. 设计食物评分系统-CSDN博客
由于数据范围很大,我们可以用一个哈希表 map 记录每个下标对应的元素,另一个哈希表套平衡树 mapSet 记录每个元素对应的下标集合。
对于 change 操作,如果 index 处已有数字,则先从 mapSet[map[index]] 中删掉 index。然后将 index 和 number 记录到 mapSet 和 map 中。
Java版:
class NumberContainers {
Map<Integer, Integer> map;
Map<Integer, TreeSet<Integer>> mapSet;
public NumberContainers() {
map = new HashMap<>();
mapSet = new HashMap<>();
}
public void change(int index, int number) {
if (map.containsKey(index)) {
int num = map.get(index);
mapSet.get(num).remove(index);
}
map.put(index, number);
mapSet.putIfAbsent(number, new TreeSet<Integer>());
mapSet.get(number).add(index);
}
public int find(int number) {
if (mapSet.containsKey(number) && !mapSet.get(number).isEmpty()) {
return mapSet.get(number).first();
}
return -1;
}
}
/**
* Your NumberContainers object will be instantiated and called as such:
* NumberContainers obj = new NumberContainers();
* obj.change(index,number);
* int param_2 = obj.find(number);
*/
Python3版:
from sortedcontainers import SortedSet
class NumberContainers:
def __init__(self):
self.map = defaultdict()
self.mapSet = defaultdict(SortedSet)
def change(self, index: int, number: int) -> None:
if index in self.map:
num = self.map[index]
self.mapSet[num].remove(index)
self.map[index] = number
self.mapSet[number].add(index)
def find(self, number: int) -> int:
if self.mapSet[number]:
return self.mapSet[number][0]
return -1
# Your NumberContainers object will be instantiated and called as such:
# obj = NumberContainers()
# obj.change(index,number)
# param_2 = obj.find(number)
解法2:懒删除堆(优先队列)
另一种做法是用堆:
- 对于 change 操作,直接往 mapHeap 中记录,不做任何删除操作;
- 对于 find 操作,查看 mapHeap 堆顶下标对应的 map 中的 元素是否和 number 相同,若不相同则意味着对应的元素已被替换成了其他值,mapHeap 堆顶存的是个垃圾数据,直接弹出堆顶;否则堆顶就是答案。
Java版:
class NumberContainers {
Map<Integer, Integer> map;
Map<Integer, Queue<Integer>> mapHeap;
public NumberContainers() {
map = new HashMap<>();
mapHeap = new HashMap<>();
}
public void change(int index, int number) {
map.put(index, number);
mapHeap.putIfAbsent(number, new PriorityQueue<Integer>());
mapHeap.get(number).offer(index);
}
public int find(int number) {
if (!mapHeap.containsKey(number)) {
return -1;
}
while (!mapHeap.get(number).isEmpty() && map.get(mapHeap.get(number).peek()) != number) {
mapHeap.get(number).poll();
}
return mapHeap.get(number).isEmpty() ? -1 : mapHeap.get(number).peek();
}
}
/**
* Your NumberContainers object will be instantiated and called as such:
* NumberContainers obj = new NumberContainers();
* obj.change(index,number);
* int param_2 = obj.find(number);
*/
Python3版:
class NumberContainers:
def __init__(self):
self.map = defaultdict()
self.mapHeap = defaultdict(list)
def change(self, index: int, number: int) -> None:
self.map[index] = number
heappush(self.mapHeap[number], index)
def find(self, number: int) -> int:
while self.mapHeap[number] and self.map[self.mapHeap[number][0]] != number:
heappop(self.mapHeap[number])
return self.mapHeap[number][0] if self.mapHeap[number] else -1
# Your NumberContainers object will be instantiated and called as such:
# obj = NumberContainers()
# obj.change(index,number)
# param_2 = obj.find(number)