元素合并_提前计算结果.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;
}