【LeetCode-系统设计】

元素合并_提前计算结果.cpp


https://leetcode.cn/problems/design-underground-system/
地铁系统跟踪不同车站之间的乘客出行时间,并使用这一数据来计算从一站到另一站的平均时间。

实现 UndergroundSystem 类:
void checkIn(int id, string stationName, int t)
通行卡 ID 等于 id 的乘客,在时间 t ,从 stationName 站进入
乘客一次只能从一个站进入
void checkOut(int id, string stationName, int t)
通行卡 ID 等于 id 的乘客,在时间 t ,从 stationName 站离开
double getAverageTime(string startStation, string endStation)
返回从 startStation 站到 endStation 站的平均时间
平均时间会根据截至目前所有从 startStation 站 直接 到达 endStation 站的行程进行计算,也就是从 startStation 站进入并从 endStation 离开的行程
从 startStation 到 endStation 的行程时间与从 endStation 到 startStation 的行程时间可能不同
在调用 getAverageTime 之前,至少有一名乘客从 startStation 站到达 endStation 站
你可以假设对 checkIn 和 checkOut 方法的所有调用都是符合逻辑的。如果一名乘客在时间 t1 进站、时间 t2 出站,那么 t1 < t2 。所有时间都按时间顺序发生


// 1、怎样将两个map的元素合并到一个map中,通过相同的索引ID
// 2、出站的时候需要计算好结果,提前将所有结果存储下来
// 3、要求平均值,需要统计出所有的区间tuple<inS, outS> 多个time, 确定数据结构map<tuple<inS, outS>, vector<time>>,是同一个ID,所以map<tuple<id, inS, outS>, vector<time>>
    // 同一个id, 就不是多个time,需要将id删除,在过程中判断id是否相同,最终还是可以确定出数据结构map<tuple<inS, outS>, vector<time>>
    // 剩下就是看自己能不能考虑到在出站的时候考虑同一个id,并把结果计算出来的问题了
// 4、出站的时候如果不存储数据,虽然能写出来,但是每次都得遍历inMap,可能会超时
class UndergroundSystem {
public:
    UndergroundSystem() {

    }
    
    map<int, tuple<string, int>> inMap; 
    void checkIn(int id, string stationName, int t) {
        inMap[id] = make_tuple(stationName, t);
    }
    
    map<int, tuple<string, int>> outMap;
    map<tuple<string, string>, vector<int>> sameInOut; 
    void checkOut(int id, string stationName, int t) {
        outMap[id] = make_tuple(stationName, t);

        // 出站的时候就把相同起始点和终止点对应的时间存储好(无序存储ID,不存的原因是结果计算的时候只看起终点)
        sameInOut[make_tuple(get<0>(inMap[id]), stationName)].push_back(t - get<1>(inMap[id]));
    }
    
    double getAverageTime(string startStation, string endStation) {
        string name = startStation + endStation;
        int result = 0;
        for (auto value : sameName[name]) {
            result += value;
        }
        return static_cast<double>(result) / sameName[name].size();
    }
};

系统设计_租房系统.cpp

/*
请你设计一个租房系统。支持以下几个函数:

boolean addRoom(int id, int area, int price, int rooms, int[] address):向系统中加入房号为 id 的房子。id:
房间编号,area:房间面积,price:房间租金,rooms:房间对应数量,address:房间平面坐标(x坐标,y坐标;长度为2)。

执行 addRoom 操作:

1)若租房系统中已经存在房号为id的房间,则更新该房间的信息为新加入的信息,同时返回false;

2)若租房系统中已经不存在房号为id的房间,则更新该房间的信息为新加入的信息,同时返回true。

boolean deleteRoom(int id):从系统中移除房号为id的房子。

1)若租房系统中已经存在房号为id的房间,则将该房间从系统移除,返回true;

2)若租房系统中不存在房号为id的房间,返回false。

int[] queryRoom(int area, int price, int rooms, int[] address, int[][] orderBy):查询满足指定规则的房间。

查询规则:

找出当前租房系统中房间面积大于等于area,租金小于等于price,房间数量等于rooms的房间,将这些房间按照orderBy指定的规则进行升序或者降序排列,orderBy的每一个元素为( parameter,order),其中parameter可能取值为1(按照面积排序) 2 (按照租金排序) 3(曼哈顿距离排序),order可能的取值1 (升序排列) -1(降序排列),曼哈顿距离由查询的address和满足面积大于等于area,租金小于等于price,房间数量等于rooms的房间对应address求解 |x1-x2|+|y1-y2|

输入: ["RentingSystem","addRoom","addRoom","queryRoom","deleteRoom"]
	  [[],[3,24,200,2,[0,1]],[1,10,400,2,[1,0]],[1,400,2,[1,1],[[3,1],[2,-1]]],[3]]

输出: [null,true,true,[1,3],true]
*/

// 涉及多个元素排序,数据结构一定是vector<tuple<>>
vec.push_back(make_tuple<ele.first, ele.second>)

class RentingSystem {
public:
    RentingSystem()
    {

    }

    // 考虑用vector存储房间信息
    // 自己思路编号放在vector中 - 编号作为vector的下标
    vector<tuple<int, int ,int, int, int>> roomSytem(1000);
    map<int, int> dict; // 统计房间是否还存在

    bool AddRoom(int id, int area, int price, int rooms, const vector<int>& address)
    {
        // 编号是否在map中(map中是否存在某个key)
        if (dict.count(id)) {
            // 采取直接赋值的方法,而不是push_back // tuple 等价 { }
            roomSytem[id] = { area, price, rooms, address[0], address[1] };
            return false;
        } else {
            roomSytem[id] = { area, price, rooms, address[0], address[1] };
            // 只能是1 不能是++ 自动覆盖信息 永远只会有一个id
            // 通过map确定当前系统是否存在id的房间(自己可能会将房间号一起push_back到vec,然后遍历vec看id是否存在)
            // 牺牲空间,代码复杂度会简单很多,思路也会清晰很多
            dict[id] = 1;
            return true;
        }
    }

    bool DeleteRoom(int id)
    {
        if (dict.count(id)) {
            dict.erase(id); //  删除操作都是通过map, roomSystem中保留房间id也没有关系(自己删除roomSystem)// 1、通过map erase方法删除元素
            return true;
        }
        return false;
    }

    vector<int> QueryRoom(int area, int price, int rooms, const vector<int>& address, const vector<vector<int>>& orderBy)
    {
        vector<int> sortRoom;
        for (auto ele : dict) {
            
            int roomId = ele.first; // 存在的房间
            int roomArea = get<0>(roomSytem[roomId]);
            int roomPrice = get<1>(roomSytem[roomId]);
            int roomRooms = get<2>(roomSytem[roomId]);
            if (roomArea >= area && roomPrice <= price && roomRooms == rooms) {
                sortRoom.push_back(roomId);
            }


            // 排序不一定要元素全在vec中
            // 
            sort(sortRoom.begin(), sortRoom.end(), [&](int aRoomId, int bRoomId){
                for (auto order : orderBy) {
                    int para = order[0];
                    int orderSort = order[1]; // 升序 降序

                    // [[3,1],[1,-1]] 表示先按照曼哈顿距离升序排列;若曼哈顿距离相同,再按照面积降序排列
                    // 每个条件需要加上面积 价格 距离不相等
                    if (para == 1) {
                        if (orderSort == 1) {
                            return get<0>(roomSytem[aRoomId]) < get<0>(roomSytem[bRoomId]);
                        } else {
                            return get<0>(roomSytem[aRoomId]) > get<0>(roomSytem[bRoomId]);
                        }
                    }

                    if (para == 2) {
                        if (orderSort == 2) {
                            return get<1>(roomSytem[aRoomId]) < get<1>(roomSytem[bRoomId]);
                        } else {
                            return get<1>(roomSytem[aRoomId]) > get<1>(roomSytem[bRoomId]);
                        }
                    }

                    int aDistance = abs(get<3>(roomSytem[aRoomId]) - address[0]) + abs(get<4>(roomSytem[aRoomId]) - address[1]);
                    int bDistance = abs(get<3>(roomSytem[bRoomId]) - address[0]) + abs(get<4>(roomSytem[aRoomId]) - address[1]);
                    if (para == 3) {
                        if (orderSort == 3) {
                            return aDistance < bDistance;
                        } else {
                            return aDistance > bDistance;
                        }
                    }

                    return aRoomId < bRoomId;
                }
            });
            return sortRoom;
        }
};

int main(int argc, const char *argv[])
{
    std::cout << "Hello World" << std::endl;


    system("pause");
    return 0;
}

系统设计_滑雪排名.cpp

/*
addRecord(int userId, int duration):实现添加运动员的滑雪成绩,可以存多个

getTopAthletes(int num):获取滑雪成绩最快的 num 名运动员的 id 数组,按滑雪成绩升序,成绩好的在前面;当成绩相同时,【先取得该最好成绩的】排在前面;当运动员不足 num 位时,按实际人数返回

queryTop3Record(int userId):查询userId的运动员的前 3 次最好成绩,按成绩升序返回,不足3次按实际返回

输入:
[“SkiRankingSystem”,“addRecord”,“addRecord”,“getTopAthletes”,“queryTop3Record”]
[[],[1,10],[2,8],[3],[1]]
输出:
[null,null,null,[2,1],[10]]

输入:
[“SkiRankingSystem”,“addRecord”,“addRecord”,“addRecord”,“getTopAthletes”,“addRecord”,“addRecord”,“addRecord”,“getTopAthletes”,“addRecord”,“queryTop3Record”,“addRecord”,“queryTop3Record”]
[[],[20,8],[22,6],[20,6],[4],[33,5],[22,9],[31,4],[4],[20,8],[20],[20,6],[20]]
输出:
[null,null,null,null,[22,20],null,null,null,[31,33,22,20],null,[6,8,8],null,[6,6,8]]
*/

// 一个人对应多条成绩记录,成绩相同时,先获取成绩的排在前面,这种套路需要手动给每条数据加一个索引,用于区分前后
// 需要找topN,<id score> index,涉及多个元素排序一定是用vector,所以数据结构定义为vector<tuple<id, score, index>>
// 从vec中找出不同的ID,就需要用一个map统计是否已经存入

class Solution {
public:
    static bool compare(tuple<int, int, int> a, tuple<int, int, int> b) {
        if (get<1>(a) == get<1>(b)) {
            return get<2>(a) < get<2>(b);
        }
        return get<1>(a) < get<1>(b);
    }

    int count = 0;
    vector<tuple<int, int, int>> system; // id(0) time(1) index(2) // 1、在类中是全局变量,基本数据库需要定义全局变量
    void AddRecord(int userId, int duration) {
        system.push_back(make_tuple(userId, duration, count++));
    }

    //map<int, int> best; // 每次查询都需要清0
    //vector<int> topN; // topN局部变量,每次计算完topN需要清0,否则会保留之前的排名结果
    vector<int> GetTopAthletes(int num) {
        map<int, bool> best; // 2、接口中需要定义局部变量,写在上面变成全局变量各种问题
        vector<int> topN;
        sort(system.begin(), system.end(), compare);
        for (auto ele : system) {
            int id = get<0>(ele);
            int score = get<1>(ele);

            if (best.count(id)) {
                continue;
            }
            topN.push_back(id);
            best[id] = true;

            if (topN.size() == num) { // 达到长度直接返回,不需遍历所有元素
                return topN;
            }
        }
        return topN;
    }

    vector<int> QueryTOP_NRecord(int userId) {
        vector<int> topScore;
        vector<int> res;
        for (auto ele : system) {
            int id = get<0>(ele);
            int score = get<1>(ele);

            if (id == userId) {
                topScore.push_back(score);
            }

            //sort(topScore.begin(), topScore.end()); // 3、排序位置错误!!!
        }
        sort(topScore.begin(), topScore.end());

        int num = (topScore.size() >= 3) ? 3 : topScore.size();
        for (int i = 0; i < num; i++) {
            //res[i] = topScore[i]; // 4、没有初始化长度,不能直接赋值,vector初始化vector<int> vec(3, 0);
            res.push_back(topScore[i]);
        }
        return res;
    }
};

// 1、单步调试很重要!真的很重要,不然都不知道自己的代码逻辑出现问题
// 2、优先一步步走,走到对应位置vec tuple都是在变量上看到,不需要通过cout输出打印,浪费时间不说,把代码搞的很乱
// 3、核对每一步上的值是否正确
// 4、花时间把mian中的调用补齐
int main()
{
    Solution *s = new Solution();
    s->AddRecord(20, 8);
    s->AddRecord(22, 6);
    s->AddRecord(20, 6);

    vector<int> res1 = s->GetTopAthletes(4);

    s->AddRecord(33, 5);
    s->AddRecord(22, 9);
    s->AddRecord(31, 4);

    vector<int> res2 = s->GetTopAthletes(4);

    s->AddRecord(20, 8);

    vector<int> res3 = s->QueryTOP_NRecord(20);

    s->AddRecord(20, 6);

    vector<int> res4 = s->QueryTOP_NRecord(20);

    system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值