leetcode 1396. Design Underground System(设计地铁系统)

An underground railway system is keeping track of customer travel times between different stations. They are using this data to calculate the average time it takes to travel from one station to another.

Implement the UndergroundSystem class:

void checkIn(int id, string stationName, int t)
A customer with a card ID equal to id, checks in at the station stationName at time t.
A customer can only be checked into one place at a time.
void checkOut(int id, string stationName, int t)
A customer with a card ID equal to id, checks out from the station stationName at time t.
double getAverageTime(string startStation, string endStation)
Returns the average time it takes to travel from startStation to endStation.
The average time is computed from all the previous traveling times from startStation to endStation that happened directly, meaning a check in at startStation followed by a check out from endStation.
The time it takes to travel from startStation to endStation may be different from the time it takes to travel from endStation to startStation.
There will be at least one customer that has traveled from startStation to endStation before getAverageTime is called.
You may assume all calls to the checkIn and checkOut methods are consistent. If a customer checks in at time t1 then checks out at time t2, then t1 < t2. All events happen in chronological order.

Example 1:

Input
[“UndergroundSystem”,“checkIn”,“checkIn”,“checkIn”,“checkOut”,“checkOut”,“checkOut”,“getAverageTime”,“getAverageTime”,“checkIn”,“getAverageTime”,“checkOut”,“getAverageTime”]
[[],[45,“Leyton”,3],[32,“Paradise”,8],[27,“Leyton”,10],[45,“Waterloo”,15],[27,“Waterloo”,20],[32,“Cambridge”,22],[“Paradise”,“Cambridge”],[“Leyton”,“Waterloo”],[10,“Leyton”,24],[“Leyton”,“Waterloo”],[10,“Waterloo”,38],[“Leyton”,“Waterloo”]]

Output
[null,null,null,null,null,null,null,14.00000,11.00000,null,11.00000,null,12.00000]

Explanation
UndergroundSystem undergroundSystem = new UndergroundSystem();
undergroundSystem.checkIn(45, “Leyton”, 3);
undergroundSystem.checkIn(32, “Paradise”, 8);
undergroundSystem.checkIn(27, “Leyton”, 10);
undergroundSystem.checkOut(45, “Waterloo”, 15); // Customer 45 “Leyton” -> “Waterloo” in 15-3 = 12
undergroundSystem.checkOut(27, “Waterloo”, 20); // Customer 27 “Leyton” -> “Waterloo” in 20-10 = 10
undergroundSystem.checkOut(32, “Cambridge”, 22); // Customer 32 “Paradise” -> “Cambridge” in 22-8 = 14
undergroundSystem.getAverageTime(“Paradise”, “Cambridge”); // return 14.00000. One trip “Paradise” -> “Cambridge”, (14) / 1 = 14
undergroundSystem.getAverageTime(“Leyton”, “Waterloo”); // return 11.00000. Two trips “Leyton” -> “Waterloo”, (10 + 12) / 2 = 11
undergroundSystem.checkIn(10, “Leyton”, 24);
undergroundSystem.getAverageTime(“Leyton”, “Waterloo”); // return 11.00000
undergroundSystem.checkOut(10, “Waterloo”, 38); // Customer 10 “Leyton” -> “Waterloo” in 38-24 = 14
undergroundSystem.getAverageTime(“Leyton”, “Waterloo”); // return 12.00000. Three trips “Leyton” -> “Waterloo”, (10 + 12 + 14) / 3 = 12

这是一个系统设计题,要设计一个地铁检票系统,每个人对应不同的id,进站checkin,会有进站人id,站名,时间。出站是checkout, 有出站id,站名,时间。
出站时间 - 进站时间= 两站之间需要的时间。
getAverageTime就是不同的人到两站之间的时间,计算出平均时间。

思路:

进站时有人物的id和进站信息,存入hashMap,
方便后面出站时 找 这个id对应的进站信息。
把进站信息设计为一个结构CheckInInfo.
那么需要一个map(id, CheckInInfo)结构

出站信息和进站信息一样,人物id, 出站站名,出站时间。

下面通过计算平均时间的要求推出出站信息的数据结构,

要计算两站之间的平均时间,
需要知道进站站名,出站站名,两站之间的总时间,经过的总人数。

两站之间的总时间,总人数需要在每次checkOut时累加。

所以在checkOut时需要找到人物id对应的进站名,进站时间,这个可以通过map(id, CheckInInfo)得到。
把当前出站时间 - 进站时间 累加到这两站的总时间上,人数+1即可。
那么出站信息CheckOutInfo结构就是(出站名,总时间,总人数)

而计算平均时间的函数参数只有进站名和出站名,
需要通过进站名找到对应的(出站名,总时间,总人数),
而为了不每次都去比较出站名是不是当前出站名,
把CheckOutInfo结构(出站名,总时间,总人数)里面的出站名提出来作为hashMap的key.
这样就可以通过站名一次性找到(总时间,总人数)。

因此CheckOutInfo结构变为(总时间,总人数),需要一个map(出站名,CheckOutInfo).

加上进站名,需要这个结构:map(进站名,map(出站名,CheckOutInfo))

通过上面设计的数据结构,
在调用函数时:
checkIn: 进站时保存(id, CheckInInfo)

checkOut: 出站时通过id找到进站站名,进站时间,
更新两站之间的总时间,总人数。
把信息保存进CheckOutInfo.
再通过进站站名保存map(进站名,map(出站名,CheckOutInfo))

getAverageTime:
计算平均时间时,通过进站站名得到map(出站名,CheckOutInfo).
通过出站站名得到CheckOutInfo,也就是得到这两站之间总的时间,总的人数。
相除得到平均时间。

class UndergroundSystem {
    Map<Integer, CheckInInfo> checkInInfo;  //id和checkIn信息
    Map<String, Map<String, CheckOutInfo>> checkInOutInfo; //checkInStation对应 checkOutStation和信息的map

    public UndergroundSystem() {
        checkInInfo = new HashMap<>();
        checkInOutInfo = new HashMap<>();
    }
    
    public void checkIn(int id, String stationName, int t) {
        checkInInfo.put(id, new CheckInInfo(id, stationName, t));
    }
    
    public void checkOut(int id, String stationName, int t) {
        //通过id找到对应的checkInInfo,并移除
        CheckInInfo curCheckIn = checkInInfo.remove(id);
        
        //通过checkOutStationName找到对应的checkInStationName, time, id等
        //刚开始还没有对应的checkOut信息时为null,要新建hashMap
        Map<String, CheckOutInfo> checkOutInfo = checkInOutInfo.getOrDefault(curCheckIn.checkInStation, new HashMap<>());  //找到checkIn对应的checkOut map
        CheckOutInfo detail = checkOutInfo.getOrDefault(stationName, new CheckOutInfo());  //找到checkOutStation对应的信息

        detail.totalTime += t - curCheckIn.checkInTime;
        detail.totalTrips ++;

        checkOutInfo.put(stationName, detail);
        checkInOutInfo.put(curCheckIn.checkInStation, checkOutInfo);
    }
    
    public double getAverageTime(String startStation, String endStation) {
        CheckOutInfo detail = checkInOutInfo.get(startStation).get(endStation);
        long totalTime = detail.totalTime;
        long totalTrips = detail.totalTrips;
        return totalTrips == 0 ? 0 : (double)totalTime / totalTrips;
    }
}

class CheckInInfo{
    int id;
    String checkInStation;
    int checkInTime;
    public CheckInInfo(int id, String stationName, int time) {
        this.id = id;
        this.checkInStation = stationName;
        this.checkInTime = time;
    }
}

class CheckOutInfo{
    long totalTime;
    long totalTrips;
    public CheckOutInfo(){}
}

在这里插入图片描述
在这里插入图片描述

方法二:

上面在计算平均时间时,通过进站名,出站名和2个hashMap能得到总时间和总人数。
还可以把 “进站名-出站名” 这个String作为key, 一步得到总时间和总人数。

那么
checkIn: 保存map(id, 进站信息)

checkOut: 通过id取得进站名,进站时间,
更新两站之间的总时间,总人数,
保存map(“进站名-出站名”, (总时间,总人数))

getAverageTime:
key=“进站名-出站名"
通过key得到(总时间,总人数)
计算平均时间。

class UndergroundSystem {
    Map<Integer, CheckInInfo> checkInInfo;  //id和checkIn信息
    Map<String, CheckOutInfo> checkInOutInfo; //key为"checkInStation-checkOutStation"

    public UndergroundSystem() {
        checkInInfo = new HashMap<>();
        checkInOutInfo = new HashMap<>();
    }
    
    public void checkIn(int id, String stationName, int t) {
        checkInInfo.put(id, new CheckInInfo(id, stationName, t));
    }
    
    public void checkOut(int id, String stationName, int t) {
        //通过id找到对应的checkInInfo,并移除
        CheckInInfo curCheckIn = checkInInfo.remove(id);
        
        String key = curCheckIn.checkInStation + "-" + stationName;
        CheckOutInfo curCheckOut = checkInOutInfo.getOrDefault(key, new CheckOutInfo());

        curCheckOut.totalTime += t - curCheckIn.checkInTime;
        curCheckOut.totalTrips ++;

        checkInOutInfo.put(key, curCheckOut);
    }
    
    public double getAverageTime(String startStation, String endStation) {
        CheckOutInfo detail = checkInOutInfo.get(startStation+"-"+endStation);
        long totalTime = detail.totalTime;
        long totalTrips = detail.totalTrips;
        return totalTrips == 0 ? 0 : (double)totalTime / totalTrips;
    }
}

class CheckInInfo{
    int id;
    String checkInStation;
    int checkInTime;
    public CheckInInfo(int id, String stationName, int time) {
        this.id = id;
        this.checkInStation = stationName;
        this.checkInTime = time;
    }
}

class CheckOutInfo{
    long totalTime;
    long totalTrips;
    public CheckOutInfo(){}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值