leetcode刷题记录09-981. 基于时间的键值存储

问题描述

设计一个基于时间的键值数据结构,该结构可以在不同时间戳存储对应同一个键的多个值,并针对特定时间戳检索键对应的值。

实现 TimeMap 类:

  • TimeMap() 初始化数据结构对象
  • void set(String key, String value, int timestamp) 存储给定时间戳 timestamp 时的键 key 和值 value
  • String get(String key, int timestamp) 返回一个值,该值在之前调用了 set,其中 timestamp_prev <= timestamp 。如果有多个这样的值,它将返回与最大  timestamp_prev 关联的值。如果没有值,则返回空字符串("")。

示例

示例 1:

输入:
["TimeMap", "set", "get", "get", "set", "get", "get"]
[[], ["foo", "bar", 1], ["foo", 1], ["foo", 3], ["foo", "bar2", 4], ["foo", 4], ["foo", 5]]
输出:
[null, null, "bar", "bar", null, "bar2", "bar2"]

解释:
TimeMap timeMap = new TimeMap();
timeMap.set("foo", "bar", 1);  // 存储键 "foo" 和值 "bar" ,时间戳 timestamp = 1   
timeMap.get("foo", 1);         // 返回 "bar"
timeMap.get("foo", 3);         // 返回 "bar", 因为在时间戳 3 和时间戳 2 处没有对应 "foo" 的值,所以唯一的值位于时间戳 1 处(即 "bar") 。
timeMap.set("foo", "bar2", 4); // 存储键 "foo" 和值 "bar2" ,时间戳 timestamp = 4  
timeMap.get("foo", 4);         // 返回 "bar2"
timeMap.get("foo", 5);         // 返回 "bar2"

提示:

  • 1 <= key.length, value.length <= 100
  • key 和 value 由小写英文字母和数字组成
  • 1 <= timestamp <= 10^7
  • set 操作中的时间戳 timestamp 都是严格递增的
  • 最多调用 set 和 get 操作 2 * 10^5 次

问题分析:

一开始,想着动用最少的脑子来解决这道中等题,直接暴力,下面先贴暴力原码。主要思想是拿timestamp为key,对应的键值对存储成pair进数组里,然后for循环遍历timestamp根据对应的key找到value。直接狠狠的超时。

然后意识到get方法的时间复杂度过高,众所周知,在查找过程中只要超时,先想想是不是自己太菜(bushi),应该第一时间想想能不能优化成二分。所以直接采用map,利用内置的lower_bound函数,具体流程直接看代码。

代码如下:

""暴力"",过了44/51的案例

class TimeMap {
public:
    map<int, vector<pair<string, string>>> mp;
    TimeMap() {

    }
    
    void set(string key, string value, int timestamp) {
        mp[timestamp].push_back({key, value});
    }
    
    string get(string key, int timestamp) {
        if(mp.find(timestamp) == mp.end())
        {
            string final = "";
            for(auto &[x, v] : mp)
            {
                if(x <= timestamp)
                    for(int i = 0; i < v.size(); i ++)
                    {
                        if(v[i].first == key)
                            final = v[i].second;
                    }
            }
            return final;
        }
        else
        {
            for(auto &v : mp[timestamp])
            {
                if(v.first == key)
                {
                    return v.second;
                }
            }
        }
        return "";
    }
};

""二分""

class TimeMap {
public:
    //意识到我们最终要在查找timestamp上花时间,直接用map存确保有序
    unordered_map<string, map<int, string>> mp;

    TimeMap() {
    }
    
    void set(string key, string value, int timestamp) {
        mp[key][timestamp] = value;  // 由于map是有序的,因此不需要vector,而值直接绑定到时间戳
    }
    
    string get(string key, int timestamp) {
        //查找mp里是否有key对应的value
        auto it = mp.find(key);
        //找到了
        if(it != mp.end()) {
            // 使用lower_bound找到存储中大于或等于timestamp的最小时间戳
            auto valueIt = it->second.lower_bound(timestamp);
            // 如果准确找到,则返回对应值
            if(valueIt != it->second.end() && valueIt->first == timestamp) {
                return valueIt->second;  
            }
            
            // 如果没有准确找到且不是首元素,找到第一个较大的元素,进行回退
            if(valueIt != it->second.begin()) {
                valueIt--;
                return valueIt->second;  // 返回小于时间戳的最近一次的值
            }
        }
        return "";  // 如果找不到元素,则返回空字符串
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值