查看: 18981| 回复: 22
跳转到指定楼层
上一主题 下一主题
收起左侧

[题目讨论] bloomberg 马拉松设计题

 
全局:

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x
第一个问题问的设计题,一个track上有很多runner,还有很多sensor,sensor可以检测到那个runner跑过了这个sensor
用这个系统生成一个dashboard显示runner现在的名次。

查之前的帖子,说有总结。但我没有找到。

有人能把总结的帖子发一下,或者说说这道题的想法么?

上一篇:关于系统设计的一个忠告
下一篇:微软online screen: Design API for email service怎么做?
全局:
我提供一个思路
先看题,假设一共有n个runner,m个sensor,runner跑的时候经过连续的sensor(不会从sensor1直接到sensor3),而我们需要实现的方法有update(i, j),即runner i 刚刚经过 sensor j;以及getRank(k)获得当下前 k 个选手的名次。

solution 1:
1. 用一个2D array(int[][] ranking , m * n)记录runner跑到哪了,以及一个长 m 的array(int[] counter)记录已有多少个runner经过当前sensor。
2. 每次update(i,j),ranking[j-1][i] = 0, ranking[j][i] = counter[i]+1;
3. 每次getRank(k),从下往上遍历每个sensor,还需将每一行根据ranking[][]的大小排序,拿出前k个。

这用做也许在m,n都比较小的时候可以,但随着m,n增多很不方便。
主要问题是,如何保持每个sensor所“拥有”的runner有先后顺序(如queue),在先后顺序的前提下如何快速删除其中某一个runner(突然跑快了),并append到下一个sensor的队列中;为了取前k个runner,当sensor较多runner比较稀疏时,如何取了一部分后知道下一个有runner的sensor是谁。

solution 2:基于double linked list, hashmap
1. 建立一个HashMap<Runner, Node>, 每个runner对应一个node,O(1)时间找到这个此runner的位置
2. 每个sensor都建立double linked list,O(1)时间删除,且始终有序。删除后加入更新的sensor链尾即可,update时间O(1)
3. 建立另一个长 k 的 double linked list,每个node代表一个sensor,将稀疏的sensor连起来
4. getRank(k)时,依次将每个sensor node中选手按许倒出即可,O(k)

第一次回帖,只是提供思路,见谅,欢迎交流。

评分

参与人数 6大米 +18 收起 理由
睡不醒的小新 + 3 很有用的信息!
滚动的西瓜 + 3 很有用的信息!
dustbin + 2 给你点个赞!
籍文同学 + 2 欢迎分享你知道的情况,会给更多积分奖励!
高渐离击筑高歌 + 5 很有用的信息!

查看全部评分

回复

使用道具 举报

全局:
  1. class LinkedList():
  2.     def __init__(self, person):
  3.         self.person = person
  4.         self.next = None
  5.         self.prev = None

  6. class Marrathon():
  7.     def __init__(self, numSensor):
  8.         self.sensorsHead = [0] * numSensor
  9.         self.sensorsTail = [0] * numSensor
  10.         self.person2Node = dict()
  11.         for i in range(numSensor):
  12.             self.head = LinkedList(-1)
  13.             self.tail = LinkedList(-1)
  14.             self.head.next = self.tail
  15.             self.tail.prev = self.head
  16.             self.sensorsHead[i] = self.head
  17.             self.sensorsTail[i] = self.tail
  18.             
  19.     def update(self, person, sensor):
  20.         if person in self.person2Node:
  21.             node = self.person2Node[person]
  22.             self.removeNode(node)
  23.             self.addNode(sensor, node)
  24.         else: # person 1st time appear
  25.             node = LinkedList(person)
  26.             self.person2Node[person] = node
  27.             self.addNode(sensor, node)
  28.         
  29.     def addNode(self, sensor, node):
  30.         tail = self.sensorsTail[sensor]
  31.         p = tail.prev
  32.         p.next = node
  33.         node.next = tail
  34.         tail.prev = node
  35.         node.prev = p
  36.         
  37.     def removeNode(self, node):
  38.         p, n = node.prev, node.next
  39.         p.next = n
  40.         n.prev = p
  41.         
  42.     def topK(self, k):
  43.         res = []

  44.         for i in range(len(self.sensorsHead) - 1, -1, -1):
  45.             if k == 0:
  46.                 break
  47.             candidate = self.sensorsHead[i].next
  48.             while candidate.person != -1 and k > 0:
  49.                 res.append(candidate.person)
  50.                 k -= 1
  51.                 candidate = candidate.next
  52.         return res

复制代码

评分

参与人数 2大米 +2 收起 理由
jamekirby + 1 给你点个赞!
kobe2452 + 1 给你点个赞!

查看全部评分

回复

使用道具 举报

推荐
Liyukuang 2019-3-8 10:46:56 | 只看该作者
全局:
今天刚面到zhe这道题,超水平发挥了。基本上需要实现两个函数 passMilestone(runner), 以及printLeadBoard()打印出所有名次排名,
数据结构用一个hash table和一个doubly linked list,Node 包含runner id, 最后一个经过的milestone id, 经过milestone时候的rank,也就是第几个经过这个打卡点的,还有pre,next指针。注意passMilestone参数只有runner,没有打卡点id,所以hash table的key是runner id,值包含milestone id和rank,每次这个函数调用时候update milestone = milestone + 1,然后查看这个milestone之前几个人经过了得到rank。然后要把自己从doubly linked list中删除,然后找到正确的位置插入。诀窍在于只需要找到和自己milestone id,对每个milestone记住第一个经过的人,这样就可以把自己插入到第一个人之前。时间复杂度O(1)。print时间复杂度O(n)。希望可以帮助到大家。

评分

参与人数 5大米 +17 收起 理由
terrymyy521 + 1 很有用的信息!
dustbin + 2 给你点个赞!
籍文同学 + 2 欢迎分享你知道的情况,会给更多积分奖励!
水鬼田 + 2 给你点个赞!
14417335 + 10 很有用的信息!

查看全部评分

回复

使用道具 举报

🔗
 楼主| insideout 2017-2-3 02:41:44 | 只看该作者
全局:
我的一个主要疑问是,这道题的实时排名是如何实现的?  两个sensor之间的runner相对位置,我不知道如何得知。
回复

使用道具 举报

🔗
notturno 2017-2-12 19:38:52 | 只看该作者
全局:
看到了就进来随便说一句,可选的data structure有几种,别用heap,前年onsite挂在这上面了

这道题最早应该是出现在13年。。
回复

使用道具 举报

🔗
lokke 2017-5-11 15:04:14 | 只看该作者
全局:
第一次回帖,如果楼主把题目说全了。
sensor可以知道runner,那么每个runner设一个counter,任何sensor检测到经过,就给counter[runner_id]++,counter最高的那个就最前面的了吧? 不太清楚相等的情况是不是按时间戳排序?如果是的话,每个sensor再有一个自己的sort就好
回复

使用道具 举报

无效楼层,该帖已经被删除
🔗
aiweiwei 2017-6-7 09:50:25 | 只看该作者
全局:
哩哩哩哩不消停 发表于 2017-2-8 14:41
我提供一个思路
先看题,假设一共有n个runner,m个sensor,runner跑的时候经过连续的sensor(不会从sensor ...

如果题目是:还要可以查询某个runer目前的名次,怎么求,时间复杂度是多少呢
回复

使用道具 举报

🔗
helloworld00 2018-3-9 20:17:30 | 只看该作者
全局:
本帖最后由 helloworld00 于 2018-3-9 20:18 编辑

写个我自己的思考,还请大神指点一下

1. sensor/check_pointer那用一个list记录当前sensor有多少个runners;并且有个hashmap记录每个runner_id 和 runner_list的iterator
2. sensor 写一个deleteRunner() ;根据提供的runnerid把当前list和hashmap上的runner_id删除 //  这个runner已经从这个sensor到了另外一个
3. MarathonBoard 的 update( runner_id, sensor_id ) 主要有2步
  3.1) 先根据runner_id 从他之前sensor list里删除
  3.2)再把这个runner_id 放到现在这个sensor_id 里的runner_list 后面去  // 假设每个新的runner都是在这个sensor的runner_list的最后

4. 最后打印top K, 假设sensor都是按先后顺序排好的(如果不是,可以把list改成multiset然后写个compartor),直接把每个sensor上的runner都打印出来就是的了







class Sensor
{
    int s_id;
    int s_distance;
    list<int> runner_list;   // a list of runner_id at this sensor/check_pointer
    unordered_map<int, list<int>::iterator> runner_m_sensor;    // {runner_id : list<runner_id>::iterator}
public:
    Sensor(int id, int dist):s_id(id), s_distance(dist){ }

    void deleteRunner(int runner_id){
        auto it = runner_m_sensor.find(runner_id);
        if (it == runner_m_sensor.end()) return;

        runner_list.erase( runner_m_sensor[runner_id] );
        runner_m_sensor.erase(runner_id);
    }
};

class MarathonBoard{
    list<Sensor> sensor_list;

    unordered_map<int, list<Sensor>::iterator> sensor_m; // {sensor_id: sensor_list::iterator}
    unordered_map<int, int> runner_m;   // {runner_id: sensor_id}

public:
    MarathonBoard(){}
    void update(int runner_id, int sensor_id){
        // 1. delete the runner from his/her previous sensor's runner list      
        int old_sensor_id = runner_m[runner_id];
        auto old_sensor_it = sensor_m[old_sensor_id];
        // delete it from previous runner list
        old_sensor_it->deleteRunner(runner_id);

        // 2. push_back(runner_id) at current sensor's runner list
        // update it to current sensor
        sensor_m[sensor_id]->runner_list.push_back(runner_id);
    }

    void printTopK(int k){
        for (auto &s : sensor_list)
        {
            for (auto &r : s.runner_list)
            {
                if (k >= 0)
                    cout << "Runner id: " << r << endl;
                k--;
            }
        }
    }
};


评分

参与人数 1大米 +2 收起 理由
lzzxgyx + 2 很有用的信息!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表