GuilinDev

Lc0635

05 August 2008

635. Design Log Storage System

存储日志,包括timestamp,然后可以按照时间粒度(year,Hour等)查询所有日志

题目给 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 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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 年开始到该时间戳的秒数。
                (long) st[1] * 31 * 24 * 60 * 60 + // 将每个月都看成 31 天,这样偏序关系仍然能够保持,只是有些整数没有对应的时间戳而已
                (long) st[2] * 24 * 60 * 60 +  // 日
                (long) st[3] * 60 * 60 + // 时
                st[4] * 60L +   // 分
                st[5];  // 秒
    }

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

    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];
//        }
        if (h.get(gra) + 1 >= 0) {
            System.arraycopy(st, 0, res, 0, h.get(gra) + 1);
        }
        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);
 */

另外的网上解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class LogSystem {

    //leetcode.com/problems/design-log-storage-system/discuss/105008/Concise-Java-Solution/107763

    private List<String[]> db;
    Map<String, Integer> unitIndexMap;

    public LogSystem() {
        db = new ArrayList<>();
        unitIndexMap = new HashMap<>();
        //init
        unitIndexMap.put("Year", 4);
        unitIndexMap.put("Month", 7);
        unitIndexMap.put("Day", 10);
        unitIndexMap.put("Hour", 13);
        unitIndexMap.put("Minute", 16);
        unitIndexMap.put("Second", 19);
    }

    public void put(int id, String timestamp) {
        db.add(new String[]{String.valueOf(id), timestamp});
    }

    public List<Integer> retrieve(String s, String e, String gra) {
        int index = unitIndexMap.get(gra);
        List<Integer> res = new ArrayList<>();
        for (String[] st : db) {
            if (st[1].substring(0, index).compareTo(s.substring(0, index)) >= 0 && st[1].substring(0, index).compareTo(e.substring(0, index)) <= 0) {
                res.add(Integer.valueOf(st[0]));
            }
        }
        return res;
    }
}

/**
 * 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);
 */