Problem 4 Design Underground System

Step 1:明确题目让你做什么,你需要干啥

  • 这道题让我们design 一个数据结构,这个数据结构有几个api

Step 2:明确API

  • void checkIn(int id, string stationName, int t)

  • void checkOut(int id, string stationName, int t)

  • double getAverageTime(string startStation, string endStation)

  • getAverageTime = 所有通过start和end的总时间/所有人的总人数

High Level

  • 需要知道,所有通过start和end的总时间 &总人数

  • 可以全部记下来?

  • 从哪里来?checkIn and checkOut

  • CheckIn能给我们什么信息?

    • 哪个人(一个人), startStation

    • 哪个人(一个人), endStation

  • 零散:不是从一个API的所有数据就可以直接计算你想得到的结果

    • getAverageTime要想有合法数据,至少得有一个人完成了进站

  • 汇总成什么信息

    • getAveragetime ==》 进站 ->出站 + 总人数 +总时间

  • 问题1:id 干嘛?真的没有用吗?

    • 你出站检票的时候,是不是得知道这个人用了多久,这个人是从哪站到了哪站

    • 如何从进站的信息中提取出,这个人的入站口和时间

    • 沟通的作用

Detail Logics

Step 1: 根据操作API--》 数据结构选择

  • API 1: getAverageTime(string, startStation, string endStation)

    • <进站 --》 出站 + 总人数 + 总时间>

    • inser + look up

    • Map<String, Map<String, Pair<总时间,总人数>>> map

    • 问题2:出站口当key可以吗?ok

    • 问题3:内层的value需要记录一个pair可以只记录一个吗?不行,每个元素都是求result必须的

  • API 2: CheckIn or CheckOut?

    • CheckIn能给我们什么信息?

      • 哪个人(一个人), startStation , 入站时间

    • CheckOut能给我们什么信息?

      • 哪个人(一个人),endStation,出战时间

    • 我要是想要更新上一步map,我能在check out更新,在check out 更新的时候

      • look up进站的信息by id

    • 进站的信息是必须记录的,但是出站的信息启示可以汇总到总的结果map里面

    • Map<Integer, 进站的信息> ==》 Map<Integer, Map<String, Integer>> checkInMap

      • Map<ID, Map<start station, time>>

Step 2: 模拟运行整个程序

  • Map<String, Map<String, Pair<总时间,总人数>>> map

  • Map<Integer, 进站的信息> ==》 Map<Integer, Map<String, Integer>> checkInMap

  • void checkIn(int id, string stationName, int t)

    • case 1: 没有

      • 直接创建一条记录<id,<startStation, time>>

    • case 2: 有

      • id: check in station 存在不存在

      • case 2.1 存在

        • update check in time

        • 如果这人没有checkOut==> 检查一下时间 -->不知道逃没逃

      • case 2.2 不存在

        • 直接创建一条记录<id, <startStation, time>> ==> update Time

  • void checkOut(int id, string stationName, int t)

    • case 1: 存在

      • 根据从checkIn的map取出Map<startStation, time>

      • 根据当前的时间和取出来的上车时间,算这个人的用时

      • 人数就是自己一个人,算一个人头

      • resultMap

        • 先看看resultMap里面有没有这个人的start station

        • case 1.1有:

          • 再看看这个上车的车站有没有一个一一映射到这个出站的station

          • case 1.1.1 有

            • 把时间累加在原来的总时间上

            • 通过的总人数 + 1

          • case 1.1.2 没有

            • create a new record

          • <startStation --> endCity, 总时间,1>

        • case 1.2没有:

          • create a new record

          • <startCity --> endCity, 总时间, 1>

    • case 2:不存在

      • new API 补票:<startStation, Time>

// Some code


```java
class UndergroundSystem {
    class Pair {
        int count;
        long totalTime;
        public Pair(int c, long t) {
            this.count = c;
            this.totalTime = t;
        }
    }
    Map<Integer, Map<String, Integer>> checkInMap;
    Map<String, Map<String, Pair>> resultMap;
    public UndergroundSystem() {
        this.checkInMap = new HashMap<>();
        this.resultMap = new HashMap<>();
    }
    
    public void checkIn(int id, String stationName, int t) {
        this.checkInMap.putIfAbsent(id, new HashMap<String, Integer>());
        this.checkInMap.get(id).put(stationName, t);
    }
    
    public void checkOut(int id, String stationName, int t) {
        Map<String, Integer> checkInInfo = this.checkInMap.get(id);
        String startStation = null;
        int startTime = 0;
        for (String key: checkInInfo.keySet()) {
            startStation = key;
            startTime = checkInInfo.get(key);
            break;
        }
        checkInMap.remove(id);
        resultMap.putIfAbsent(startStation, new HashMap<String, Pair>());
        Map<String, Pair> checkOutInfo = resultMap.get(startStation);

        if (checkOutInfo.containsKey(stationName)) {
            Pair current = checkOutInfo.get(stationName);
            current.count++;
            current.totalTime += (t- startTime);
            checkOutInfo.put(stationName, current);
        }else{
            checkOutInfo.put(stationName, new Pair(1, t- startTime));
        }
    }
    
    public double getAverageTime(String startStation, String endStation) {
        if (!resultMap.containsKey(startStation)) {
            return -1.0;
        }
        Map<String, Pair> checkOutInfo = resultMap.get(startStation);
        Pair result = checkOutInfo.get(endStation);

        if (result == null) {
            return -1.0;
        } else {
            return (double)(result.totalTime)/(result.count);
        } 
    }
}
```

Last updated