LeetCode——981. 基于时间的键值存储(Java)

题目描述

题干:
创建一个基于时间的键值存储类 TimeMap,它支持下面两个操作:
1. set(string key, string value, int timestamp)
存储键 key、值 value,以及给定的时间戳 timestamp。
2. get(string key, int timestamp)
返回先前调用 set(key, value, timestamp_prev) 所存储的值
其中 timestamp_prev <= timestamp。
如果有多个这样的值,则返回对应最大的  timestamp_prev 的那个值。
如果没有值,则返回空字符串("")。

示例1:
输入:inputs = ["TimeMap","set","get","get","set","get","get"],
inputs = [[],["foo","bar",1],["foo",1],["foo",3],
["foo","bar2",4],["foo",4],["foo",5]]
输出:[null,null,"bar","bar",null,"bar2","bar2"]
解释:  
TimeMap kv;   
kv.set("foo", "bar", 1); // 存储键 "foo" 和值 "bar" 以及时间戳 timestamp = 1   
kv.get("foo", 1);  // 输出 "bar"   
kv.get("foo", 3); 
// 输出 "bar" 因为在时间戳 3 和时间戳 2 处没有对应 "foo" 的值
//所以唯一的值位于时间戳 1 处(即 "bar")   
kv.set("foo", "bar2", 4);   
kv.get("foo", 4); // 输出 "bar2"   
kv.get("foo", 5); // 输出 "bar2"   

示例2:
输入:inputs = ["TimeMap","set","set","get","get","get","get","get"]
inputs = [[],["love","high",10],["love","low",20],["love",5],
["love",10],["love",15],["love",20],["love",25]]
输出:[null,null,null,"","high","high","low","low"]

题解思路

设计TimeMap类,因为有三个变量需要考虑,所以我们把时间戳和value先分为一组,再和key分为一组

因为时间戳和value都需要进行判断,这里我们采用Pair(匹配)来存储这对键值对,将value作为key

之后用HashMap来存储key和Pair,这就完成了结构的设计,自己重写时间戳比较方法即可

正确代码

class TimeMap {

    /**
     * 自定义匹配方法存储value和时间戳
     * 继承Comparable接口实现时间戳比较
     */
    class Pair implements Comparable<Pair> {

        // 声明value和时间戳
        int timestamp;
        String value;

        // 构造函数
        public Pair(int timestamp, String value) {
            this.timestamp = timestamp;
            this.value = value;
        }

        // 重写HashCode方法
        public int hashCode() {
            return timestamp + value.hashCode();
        }

        // 重写equals方法
        public boolean equals(Object obj) {
            if (obj instanceof Pair) {
                Pair pair = (Pair) obj;
                return this.timestamp == pair.timestamp && this.value.equals(pair.value);
            }
            return false;
        }

        // 继承Comparable接口必须重写compareTo方法制定比较规则
        @Override
        public int compareTo(Pair pair) {
            if (this.timestamp != pair.timestamp) {
                return timestamp - pair.timestamp;
            } else {
                return this.value.compareTo(pair.value);
            }
        }
    }

    Map<String, List<Pair>> map;

    /**
     * 将value和timetamp存放在Pair中,方便get得到之前的value
     * 将key和Pair放入Map中方便通过key寻找value匹配组
     */
    public TimeMap() {
        map = new HashMap<String, List<Pair>>();
    }

    public void set(String key, String value, int timestamp) {
        List<Pair> pairs = map.getOrDefault(key, new ArrayList<Pair>());
        pairs.add(new Pair(timestamp, value));
        map.put(key, pairs);
    }

    // 返回上一个时间戳的value
    public String get(String key, int timestamp) {
        List<Pair> pairs = map.getOrDefault(key, new ArrayList<Pair>());
        // 默认最大字符串,保证只能得到之前的时间戳
        Pair pair = new Pair(timestamp, String.valueOf((char) 127));
        int i = binarySearch(pairs, pair);
        if (i > 0) {
            return pairs.get(i - 1).value;
        }
        return "";
    }

    // 二分查找以前set过的value
    // 用重写的compareTo比较得到相同value的下一个时间戳
    // 如果没有同value的时间戳,二分查找上一个value
    private int binarySearch(List<Pair> pairs, Pair target) {
        int low = 0, high = pairs.size() - 1;
        if (high < 0 || pairs.get(high).compareTo(target) <= 0) {
            return high + 1;
        }
        while (low < high) {
            int mid = (high - low) / 2 + low;
            Pair pair = pairs.get(mid);
            if (pair.compareTo(target) <= 0) {
                low = mid + 1;
            } else {
                high = mid;
            }
        }
        return low;
    }
}


总结

第一次接触到Pair(匹配),java也自带了简单的Pair类型,只有简单的key和valu属性

pair和Map都是键值对结构,不过Pair适用于key和value都具有各自意义的情况,灵活性更高

并且继承自定义的比较方法的Comparable接口需要重写compareTo方法,一个设计两种结构

如果文章存在问题或者有更好的题解,欢迎在评论区斧正和评论,各自努力,你我最高处见
posted @ 2021-07-10 08:50  21岁还不是架构师  阅读(70)  评论(0编辑  收藏  举报