【LeetCode - 635】设计日志存储系统

1、题目描述

在这里插入图片描述

2、解题思路

  重新理解一下题意:

  题目给 Put 输入为一个键值对,key 为 id,value 为一个字符串,表示时间戳;

  题目从 Retrieve 获取一个 id,参数 granularity 表示起点从该级往下视为 0,终点从该级往下视为“满”,例如:“2016:01:01:01:01:01” 和 “2017:01:01:23:00:00”,如果 granularity 为 “YEAR” ,则把这两个字符串看成 “2016:00:00:00:00:00” 和 “2017:12:31:23:59:59”。

  题目的难点在于如何根据给定的起点、终点和 granularity 获取 id。

  考虑到字符串比较大小不方便,把时间戳转成一个数字,题目注释说给定的年份是 2000 年到 2017 年,我们可以把时间戳改成从 1999 年开始的秒数。

  例如时间戳为:“2016:01:01:00:00:00”,先转成 int 数组:st = [2016, 1, 1, 0, 0, 0],接着计算出它从 [1999,0,0,0,0,0] 开始的秒数,即:

  (st[0] - 1999L) * (31 * 12) * 24 * 60 * 60 + // 年
  st[1] * 31 * 24 * 60 * 60 + // 月
  st[2] * 24 * 60 * 60 + // 日
  st[3] * 60 * 60 + // 时
  st[4] * 60 + // 分
  st[5]; // 秒

  把时间戳对应的秒数和 id 存储到一个 list 中。

  使用 Retrieve 函数时,计算出 start 对应的秒数和 end+1 对应的秒数,然后从 list 中找到这两个秒数之间的时间戳的 id 即可。

3、解题代码

public class LogSystem {
    // [0] 为时间戳,[1] 为 id
    ArrayList<long[]> list;

    public LogSystem() {
        list = new ArrayList<long[]>();
    }

    /**
     * "2016:01:01:00:00:00" 转为 [2016, 1, 1, 0, 0, 0],再转为秒数,存入 list
     * @param id
     * @param timestamp
     */
    public void put(int id, String timestamp) {
        String[] strs = timestamp.split(":");
        int[] st = new int[strs.length];
        for (int i = 0; i < strs.length; i++) {
            st[i] = Integer.parseInt(strs[i]);
        }
        list.add(new long[]{convert(st), id});
    }

    /**
     * 将时间戳转换为从 1999 年开始到该时间戳的秒数
     *
     * @param st
     * @return
     */
    public long convert(int[] st) {
        st[1] = st[1] - (st[1] == 0 ? 0 : 1);
        st[2] = st[2] - (st[2] == 0 ? 0 : 1);
        return (st[0] - 1999L) * (31 * 12) * 24 * 60 * 60 + // 由于本题中年份的限制在 [2000, 2017] 之间,因此我们可以将时间戳转换为从 1999 年开始到该时间戳的秒数。
                st[1] * 31 * 24 * 60 * 60 + // 将每个月都看成 31 天,这样偏序关系仍然能够保持,只是有些整数没有对应的时间戳而已
                st[2] * 24 * 60 * 60 +  // 日
                st[3] * 60 * 60 + // 时
                st[4] * 60 +   // 分
                st[5];  // 秒
    }

    /**
     * 返回在给定时间区间内的所有日志的 id
     *
     * @param s   start 、 end 和 timestamp 的格式相同
     * @param e
     * @param gra granularity 表示考虑的时间级
     * @return
     */
    public List<Integer> retrieve(String s, String e, String gra) {
        List<Integer> ans = new ArrayList();
        long start = granularity(s, gra, false);
        long end = granularity(e, gra, true);
        for (int i = 0; i < list.size(); i++) {
            // 注意 end 没有等于
            if (list.get(i)[0] >= start && list.get(i)[0] < end)
                ans.add((int) list.get(i)[1]);
        }
        return ans;
    }

    public long granularity(String s, String gra, boolean end) {
        HashMap<String, Integer> h = new HashMap<>();
        h.put("Year", 0);
        h.put("Month", 1);
        h.put("Day", 2);
        h.put("Hour", 3);
        h.put("Minute", 4);
        h.put("Second", 5);
        String[] res = new String[]{"1999", "00", "00", "00", "00", "00"};
        String[] st = s.split(":");
        for (int i = 0; i <= h.get(gra); i++) {
            res[i] = st[i];
        }
        int[] t = new int[res.length];
        for (int i = 0; i < res.length; i++) {
            t[i] = Integer.parseInt(res[i]);
        }
        if (end) {
            t[h.get(gra)]++;
        }
        return convert(t);
    }
}

/**
 * Your LogSystem object will be instantiated and called as such:
 * LogSystem obj = new LogSystem();
 * obj.put(id,timestamp);
 * List<Integer> param_2 = obj.retrieve(s,e,gra);
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值