LeetCode 2349. 设计数字容器系统

2349. 设计数字容器系统

设计一个数字容器系统,可以实现以下功能:

  • 在系统中给定下标处 插入 或者 替换 一个数字。
  • 返回 系统中给定数字的最小下标。

请你实现一个 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)

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值