Onsite 面经
Onsite 1. 跪 2017-10-19
1 第一轮:老白,简单问了一下简历后design,要求是设计一个app让人在搭uber车的时候玩游戏,具体什么游戏无所谓。我跟他交流一下后,同意相当于在uber app里面再调一个app玩游戏,但是可以access uber app里面的用户信息什么的,挑了设计中国象棋(其实其他游戏也行,无所谓),从澄清use case开始,估算QPS和数据量什么的,再扯到后端的cache/DB这些。老白还算nice,中间问问题不是特别尖锐,自我感觉还行。
这道题目没发准备啊,我能怎么答。那就我准备针对uber pool出一个你画我猜得游戏了。
2 第二轮:老白,hiring manager,就是问简历上的东西还有一些behavior什么的,最后问了些team的情况和uber的culture这类问题。
hmmm, 仍然属于没法准备。
3 第三轮:年轻三哥,先问了怎么设计load balancer,讲了一些主要的算法,20分钟左右。然后问知不知道cache,都有些什么cache,主要讲了LRU/LFU,以为要让写LRU,结果让写LFU,白板写的。关键剩的时间不多了,跟他讲了用的hash table + double-ended linked list,分析清楚了怎么work,最后只写了1个半的function,这里怀疑可能会被黑,尼玛让写LFU不早点弄,非要扯掉一大半的时间才开始写code
好的今晚学习了一下load balancing。
然后我们来写一下LRU cache吧。
class LRUCache(object):
def __init__(self, capacity):
"""
:type capacity: int
"""
self.dic = {}
self.array = []
self.capacity = capacity
def get(self, key):
"""
:type key: int
:rtype: int
"""
if key in self.dic:
self.array.remove(key)
self.array.insert(0, key)
return self.dic[key]
else:
return -1
def put(self, key, value):
"""
:type key: int
:type value: int
:rtype: void
"""
if key in self.dic:
self.array.remove(key)
self.array.insert(0, key)
else:
if len(self.array) == self.capacity:
del self.dic[self.array.pop()]
self.array.insert(0, key)
else:
self.array.insert(0, key)
self.dic[key] = value
s = LRUCache(2)
s.put(1, 1)
s.put(2, 2)
print s.get(2)
s.put(3, 3)
print s.get(2)
s.put(4, 4)
print s.get(1)
print s.get(3)
print s.get(4)
LFU 有一个test case就是过不了。放弃了!!有一个哥哥的答案写得很好。有空照着写一个。
class Node():
def __init__(self, key, val):
self.cnt = 1
self.key = key
self.val = val
self.left = None
self.right = None
def __repr__(self):
return repr(self.val)
class LFUCache(object):
def __init__(self, capacity):
"""
:type capacity: int
"""
self.capacity = capacity
self.head = None
self.tail = None
self.dic = {}
def get(self, key):
"""
:type key: int
:rtype: int
"""
if key not in self.dic:
return -1
else:
node = self.dic[key]
node.cnt += 1
self.moveForward(node)
return node.val
def put(self, key, val):
"""
:type key: int
:type val: int
:rtype: void
"""
if not self.capacity:
return
if not self.dic:
node = Node(key, val)
self.dic[key] = node
self.head = node
self.tail = node
elif key not in self.dic:
node = Node(key, val)
if len(self.dic) == self.capacity:
self.replaceTail(node)
else:
self.tail.right = node
node.left = self.tail
self.tail = node
self.moveForward(node)
self.dic[key] = node
else:
node = self.dic[key]
node.val = val
node.cnt += 1
self.moveForward(node)
def moveForward(self, node):
if not node.left:
return
else:
while node.left and node.cnt >= node.left.cnt:
if self.tail == node:
self.tail = node.left
self.swapNode(node.left, node)
if not node.left:
self.head = node
def swapNode(self, left, right):
leftLeft = left.left
rightRight = right.right
left.left = right
left.right = rightRight
right.left = leftLeft
right.right = left
if rightRight:
rightRight.left = left
if leftLeft:
leftLeft.right = right
def replaceTail(self, node):
tail = self.tail
pre = tail.left
if pre:
pre.right = node
node.left = pre
else:
self.head = node
self.tail = node
del self.dic[tail.key]
s = LFUCache(3)
s.put(1, 1)
s.put(2, 2)
s.put(3, 3)
s.put(4, 4)
print s.get(4)
print s.get(3)
print s.get(2)
print s.get(1)
s.put(5, 5)
print s.get(1)
print s.get(2)
print s.get(3)
print s.get(4)
print s.get(5)
第四轮:老白,问了些简历之后来了个小的design,怎么实现一个系统,如果key不在里面就新加一个entry并返回true,如果key在里面就直接返回false,类似unix系统里的touch这个命令。先讲了单机版的,主要focus在write lock怎么整;然后scale,我是用consistent hashing做的。这个老白挺nice的,一旦他觉得我懂某个东西,就认可,然后不再追问下去了。最后剩了15分钟左右聊天。
hmmm, 完全没法准备。
第五轮:年纪大的三哥,在硅谷工作多年了。出了个题是只有一个院子,两个人要遛狗,两人的狗不合,所以不能同时在院子里,这两个人各有两面旗子,只能通过举旗来通信。其实就是多线程的信号灯问题,写了代码,并walk through。最后剩下10分钟左右聊天。
这都什么抽象题啊。随便写了一个。
class Garden(object):
def __init__(self):
self.in_use = False
self.owner = None
def raise_flag(self, person):
if self.in_use:
return False
else:
self.in_use = True
self.owner = person
def is_available(self):
return not self.in_use
def exit(self, person):
if person == self.owner:
self.in_use = False
self.owner = None
g = Garden()
print g.raise_flag('a')
print g.is_available()
print g.exit('b')
print g.is_available()
print g.exit('a')
print g.is_available()
第六轮:小白,他在1455那个楼,所以视频聊的。纯behavior,谈了team work,怎么处理冲突,以及uber的culture这些问题。这轮本来只有45分钟,到时候了本来安排是我的recruiter跟我聊一下送人的,但他一直没来,这个小白陪着我多聊了15分钟直到他的会议室有meeting把他踢出去了,这15分钟有在kill some time的感觉,略有点尴尬。最后是coordinator来把我送走的,说1天左右出结果。
Onsite 2. 跪。 2017-12-11
感觉Uber现在面试都好迷啊!
1: manager 问 BQ,project。
无法准备
2:问系统设计:问如何设计一个系统,给你task come in,在spark里跑,跑完有一些log,apply ML model 去分析这些log。他问得非常混乱,我就说写一些script就都可以操作了。他又临时改主意了,
无法准备
问怎么统计一个月里uber rider发出的打车request。我说用什么DB,然后去DB里检索就行。然后他又问了一个地区DB不够大怎么办?
3:game of life
这道题还是有点经典的!
class Solution(object):
def gameOfLife(self, board):
"""
:type board: List[List[int]]
:rtype: void Do not return anything, modify board in-place instead.
"""
if not board or not board[0]:
return
for i in range(len(board)):
for j in range(len(board[0])):
cnt = 0
for d, p in [(1, 0), (-1, 0), (0, 1), (0, -1), (1, 1), (-1, 1), (1, -1), (-1, -1)]:
r, c = i+d, j+p
if 0 <= r < len(board) and 0 <= c < len(board[0]) and board[r][c] & 1:
cnt += 1
if board[i][j] & 1:
if cnt == 2 or cnt == 3:
board[i][j] = board[i][j] ^ 2
elif cnt == 3:
board[i][j] = board[i][j] ^ 2
for i in range(len(board)):
for j in range(len(board[0])):
board[i][j] = board[i][j] >> 1
return board
s = Solution()
print s.gameOfLife([[1,1],[1,0]])
4: level order print BST
我靠,为什么当年考我那么难!
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def levelOrderBottom(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
if not root:
return []
res = []
q = [root]
while q:
length = len(q)
curLevel = []
for i in range(length):
tmp = q.pop(0)
curLevel.append(tmp.val)
if tmp.left:
q.append(tmp.left)
if tmp.right:
q.append(tmp.right)
res.append(curLevel)
return res
a, b, c = TreeNode(1), TreeNode(2), TreeNode(3)
b.left, b.right = a, c
s = Solution()
print s.levelOrderBottom(b)
5:一个数组,print top k freq的数。
强还是py强啊!
from collections import Counter
class Solution(object):
def topKFreq(self, k, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
return [i[0] for i in Counter(nums).most_common(k)]
s = Solution()
print s.topKFreq(2, [1, 2, 3, 1])