folder_open

面試雜記

arrow_right
article

面試心得–SWAG(爍特/SOAT Co.)

面試心得–SWAG(爍特/SOAT Co.)

2021/11/05~2021/11/26【Senior Backend Engineer】錄取

職缺介紹

#

詳見官方徵才訊息-Senior Backend Engineer by SWAG (HR) 21 7 月, 2021open_in_new

第一輪線上面試

#

第一關面試就有三位真人面試官,不用面對冷冰冰的 Online Judge System,由於面試官皆沒有露面,單純由聲音及交談的口氣聽起來都十分友善,題目是由其中的兩位面試官一人負責一題,詳細內容如下列:

Add Two Numbers

#

# You are given two non-empty linked lists representing two non-negative integers.
# The digits are stored in reverse order, and each of their nodes contains a single digit.
# Add the two numbers and return the sum as a linked list.
#
# input:
# node1: 3 -> 2 -> 1
# node2: 8 -> 5 -> 6
#
# output: 1 -> 8 -> 7
def add_numbers_linklist(node_1, node_2):
pass

LRU Cache

#

"""
Implement a Least Recently Used (LRU) cache.
* The cache is initialized with a maximum capacity `size`
* When the number of items in the cache reach `size`, remove the item that was least recently accessed.
Methods
* get(key): Get the value for `key` from the cache. Return `None` if not found
* put(key, value): Add `key` to cache with value `value`.
"""
class LRU:
pass

第二輪現場面試

#

技術面試(英文聽力中文口說)

#

三位面試官分別一人問完一系列的問題

  • GIL
  • 你覺得 python 算是快的語言嗎?
  • 你覺得 python 適合做 web 嗎?
  • 你覺得開發應用程式使用 nodejs 與 python 的利弊?
  • 解釋 ACID
  • 解釋 CAP
  • 你用過 Celery 嗎? 請說明一下 Message Queue 的運作
  • 你聽過 PgBouncer 嗎?
  • 現職的 Work flow
  • 履歷上提到有帶人,請分享一下如何運作的?
  • 最近三個月曾學過什麼?
  • 期望在 Swag 學到什麼?

白板題

#

開場的題目是 Leetcode 經典題 1. Two Sumopen_in_new 的變化題,不用找出所有的數字組合,只需要檢查存不存在任意組合。

# Example 1
Input: [1,1,1,3], 4
Output: True
# Example 2
Input: [1,1,1,3], 5
Output: False

接著是進階題,一樣是來自 Leetcode 的題目 15. 3Sumopen_in_new 進行改編,只要檢查是否存在三個數字總和為目標值即可。

# Example 1
Input: [1,1,1,3], 4
Output: False
# Example 2
Input: [1,1,1,3], 5
Output: True

System Design

#

1M Active User
1K QPS for whole backend server
請設計一個 Rate Limiter。

人資面試

#

主要是文化適性相關問答。

總結

#

面試過程接觸到的人員,不論是人資或是工程師,全部都散發著友善、信任及尊重,整體而言是非常舒服的面試體驗。

技術面試不搞前測,直接線上一小時與真人面試官用刷題互動;第一輪面試當天就邀約二面,反應非常俐落敏捷不掉漆;二面當天,人資竟然不是坐在辦公室等人按門鈴,而是準時站在門禁附近等待面試者;人資知道我想等領完現職年終再報到,主動提議討論是否接受由 Swag 負擔,沒有任何為難或情緒勒索。以上種種實例,都讓人覺得獲得前所未有的尊重,原來面試可以這麼大方、這麼高尚、這麼得體、這麼禮貌不做作、這麼香,竟然還不失專業。

這麼棒的面試體驗,筆者真心建議讀者們用行動來支持!

核薪結果

#

  • 本薪:110k/mth×16mth/annum=1.76m/annum110k/mth \times 16mth/annum = 1.76m/annum
  • 獎金:依工作績效

面試結果及時程

#

  • 2021/11/05 投遞履歷
  • 2021/11/09 邀請第一輪線上面試
  • 2021/11/16 第一輪線上面試,邀請第二輪面試
  • 2021/11/18 第二輪現場面試
  • 2021/11/26 錄取,薪資協議未達成共識,待重新協調
  • 2021/11/30 收到新的 Offer 報價,預計 12/03 回覆
  • 2021/12/03 接受 Offer
  • 2021/12/07 收到正式 Offer Letter
  • 2022/01/18 收到報到通知信件,預計 2022/02/14 報到
  • 2022/02/07 因接受其他 Offer,發信婉拒 Swag 的 Offer
  • 2022/02/10 人資來電訪問婉拒 Offer 的細節

附錄:第一輪線上面試題目參考解答

#

Add Two Numbers

#

本命題與 Leetcode 2. Add Two Numbersopen_in_new 相似

class Node:
def __init__(self, val:int, next_):
self.next = next_
self.val = val
def add_numbers_linklist(node_1, node_2):
c = 0
head_dummy = Node(0, None)
head_ans = head_dummy
head_1, head_2 = node_1, node_2
while head_1 != None and head_2 != None:
s = head_1.val + head_2.val + c
c = s // 10
v = s % 10
head_ans.next = Node(v, None)
head_ans = head_ans.next
head_1 = head_1.next
head_2 = head_2.next
while head_1 != None:
s = head_1.val + c
c = s // 10
v = s % 10
head_ans.next = Node(v, None)
head_ans = head_ans.next
head_1 = head_1.next
while head_2 != None:
s = head_2.val + c
c = s // 10
v = s % 10
head_ans.next = Node(v, None)
head_ans = head_ans.next
head_2 = head_2.next
if c > 0:
head_ans.next = Node(c, None)
return head_dummy.next
h1 = Node(9, Node(9, Node(9, Node(9, None))))
h2 = Node(9, Node(9, Node(9, None)))
ans = add_numbers_linklist(h1, h2)
"""
9999 <- h1
999 <- h2
-----
10998
"""
print(ans.val)
print(ans.next.val)
print(ans.next.next.val)
print(ans.next.next.next.val)
print(ans.next.next.next.next.val)
# t = O(m + n)
# s = O(max(m, n))

LRU Cache

#

本命題與 Leetcode 146. LRU Cacheopen_in_new 相似

以下解法為面試當下所寫,並非最優解。

from typing import Any, Optional
class LRU:
def __init__(self, size:int):
self.size = size
self.container = {}
self.ordered_keys = [] # least recently used ... non least recently used
def get(self, key:str) -> Optional[Any]:
result = self.container.get(key)
if result is not None:
self._sync(key)
return result
def put(self, key:str, value:Any):
if key not in self.container and len(self.container) == self.size:
self._evict()
self.container[key] = value
self.ordered_keys.insert(0, key)
self._sync(key)
def _evict(self):
key = self.ordered_keys.pop(-1)
del self.container[key]
def _sync(self, key:str):
self.ordered_keys.remove(key) # O(size) -> O(log(size))
self.ordered_keys.insert(0, key)
cache = LRU(3)
cache.put('A', 'AA')
cache.put('B', 'BB')
cache.put('C', 'CC')
print(cache.get('A'))
print(cache.get('B'))
print(cache.get('C'))
cache.put('D', 'DD')
print(cache.get('A')) # None
print(cache.get('D')) # DD
cache.put('D', 'DDDD')
print(cache.get('B')) # BB
print(cache.get('D')) # DDDD