微软offer养成计之笔经分享
软软子的校招活动越来越丰富了,作为微软第一站姐表示无比欣慰!
这次的offer养成计也是微软给小朋友们一次熟悉笔面试流程的机会,于是毫不犹豫就上车了。
ps:本贴是在所有同学笔试结束后才发出来的,坚决保卫笔试的公正哦。希望为没参加的盆友们参考一下题目,以及期待和参加的盆友们一起探讨!
pps:有想投微软PM的兄弟姐妹们请联系我!可以一起准备哦 ღ( ´・ᴗ・` )
笔试介绍
- 平台:Codility
- 时长:130min,任选时间进入
- 题量:3道题,个人感受是1 easy + 1 medium + 1 hard,难度均衡得挺好
- 日期:2022年7月15日
笔试经验
- 平常做leetcode时,我一直是白板做题。但是毕竟是笔试,IDE不用白不用^ ^,所以我都先在IDE中写好测试好,然后粘贴到codility中。不然我担心自己不小心按到codility的提交按钮sos
- 我不了解面试官在筛选的时候,有多大比重会考虑做题速度(这个我打算后续咨询一下!)。但无论如何,我依然选择略牺牲速度来提高代码的优美性,能加的注释全都加得整整齐齐的。
题解分享
- 以下仅为个人解法,如果代码有错误(最好不要qwq) or 有更优的解法,欢迎大家在评论区提出!
- 我写python比较顺手,也欢迎大家提出其他语言的解法。
T1:气球走开!
- 题目:
- 给定字符串
S
,只由大写字母组成,每次移走一个BALLOON
(不用在意字母顺序),问可以移走几个BALLOON
- 给定字符串
- 限制:
S: [1, 2 x 10^5]
- 思路:
- 遍历字符串
S
,记录S
中每个字母出现的次数。 - 对于
BALLOON
中的每个字符,计算S
中该字符的数目能够构成几个BALLOON
- 根据木桶原理,取这些字符分别能构成
BALLOON
的个数的最小值,即为结果
- 遍历字符串
- 复杂度:
- 时间复杂度:
O(n)
,n
为S
的长度 - 空间复杂度:
O(|∑|)
,∑
是字符集,本题为26个大写字母
- 时间复杂度:
# you can write to stdout for debugging purposes, e.g. # print("this is a debug message") from collections import defaultdict def solution(S): # Time complexity: O(n), where n represents the length of S # Space complexity: O(|Sigma|), where Sigma is 26 # step1: build a dict of 'balloon' word = defaultdict(int) word['B'] = 1 word['A'] = 1 word['L'] = 2 word['O'] = 2 word['N'] = 1 # step2: build another dict of the frequency of all the characters in S counter = defaultdict(int) for ch in S: counter[ch] += 1 # step3: traverse all the characters, calculate how much balloon can construct only considering this character # and the min value will be the answer min_num = float('inf') for ch in word: min_num = min(min_num, counter[ch] // word[ch]) # print(ch, counter[ch], word[ch], counter[ch] // word[ch]) return min_num S = 'BAONXXOLL' S = 'BAOOLLNNOLOLGBAX' S = 'QAWABAWONL' S = 'ONLABLABLOON' S = 'BALLOON' S = '' res = solution(S) print(res)
T2:两只跳跳蛙
- 题目:
- 给定一排荷叶
blocks[]
,值代表荷叶的高度。 - 青蛙从荷叶
i
跳到荷叶j
的条件是:i
j
相邻,且blocks[j] >= blocks[i]
。 - 对于荷叶
i
和j
(i <= j
),两片荷叶的距离为j - i + 1
。 - 请问:有两只青蛙初始站在同一片荷叶上,它们俩可以按照上述规则分别跳跃,求两只青蛙的可能的最远距离。
- 给定一排荷叶
- 举例:
blocks = [1, 5, 5, 2, 6]
,最好的情况是两只青蛙初始化站在第3
片荷叶上(即高度为2),一只向左跳2次,一只向右跳1次,最终的距离是2+1+1=4
- 限制:
N <= 2*10^5
blocks[i] <= 1*10^9
- 思路:
- 计算以
i
为起点,向左和向右分别能跳多少步,两者相加再加1就是从该点初始的最远距离。 - 所有的最远距离取最大值即为结果。
- 计算以
- 复杂度:
- 时间复杂度:
O(n)
- 空间复杂度:
O(n)
- 时间复杂度:
# Remember, all submissions are being checked for plagiarism. # Your recruiter will be informed in case suspicious activity is detected. # you can write to stdout for debugging purposes, e.g. # print("this is a debug message") def solution(blocks): # Task: find the longest possible distance between two frogs # Limit: N <= 2*10^5, blocks[i] <= 1*10^9 # Method: starting from each block[i], find the longest steps jumping to the left, and the longest steps to the right. # Add them together and add one. The longest will be the answer # Time Complexity: O(n) # Space Complexity: O(n). I'm not sure if there exists a method with more efficient space complexity. n = len(blocks) # step1: find the longest steps jumping to the left # `jump_to_left[i]` means how many steps the frog can jump to the left jump_to_left = [0] * n sum_ = 0 for i in range(1, n): # the current block is no higher than the left one if blocks[i] <= blocks[i - 1]: # can jump one more block sum_ += 1 jump_to_left[i] = sum_ else: sum_ = 0 # step2: find the longest steps jumping to the right # `jump_to_right[i]` means how many steps the frog can jump to the right jump_to_right = [0] * n sum_ = 0 for i in range(n-2, -1, -1): # the current block is no higher than the right one if blocks[i] <= blocks[i + 1]: # can jump one more block sum_ += 1 jump_to_right[i] = sum_ else: sum_ = 0 # step3: find the longest distance between the two frogs res = 0 for i in range(n): res = max(res, jump_to_left[i] + jump_to_right[i] + 1) return res blocks = [2, 6, 8, 5] # blocks = [1, 5, 5, 2, 6] # blocks = [1, 1] # blocks = [1] # blocks = [1, 2, 3] # blocks = [3, 4, 1, 6, 5, 2, 7] res = solution(blocks) print(res)
T3:三点共线
- 题目:
- 给定二维平面上的点坐标的列表
A
,A[i].x
表示第i
个点的横坐标,A[i].y
表示第i
个点的纵坐标。A
中的点没有重合 - 求这些点中,有多少个三元组,满足这三点共线。
- 如果答案超过10**8,返回-1。
- 给定二维平面上的点坐标的列表
- 举例:
- 假设点集如上图所示,结果将返回
6
,代表有6个三元组。它们分别是(A[0], A[1], A[2])
(A[0], A[1], A[3])
(A[0], A[2], A[3])
(A[1], A[2], A[3])
(A[2], A[4], A[5])
(A[3], A[5], A[6])
- 限制:
n <= 10^3
, 意味着不能用O(n^3)
的暴力法A.x, A.y < 10^4
- 思路:
- 假设结果为
res
。对于每个点i
,- 建立哈希表
slopes
,记录每个斜率出现的次数 - 遍历点
j
(j > i
),求出i
与j
的斜率,设为slope
,那么,slopes[slope]
应该加一。 - 遍历所有的斜率,设某斜率
slope
对应num
个点,那么包含点i
在内的斜率为slope
的三元组数目为C(num, 2) = num * (num - 1) // 2
。res
加上该值即可。
- 建立哈希表
- 假设结果为
- 难点:
- 斜率涉及到小数精度问题,所以这里
slopes
中不存真正的斜率,而是存坐标差。具体而言,计算dx
和dy
,然后求最大公约数进行约分,以字符串的形式存到slopes
中。 - 可以类比leetcode 149. 直线上最多的点数的。
- 斜率涉及到小数精度问题,所以这里
- 复杂度:
- 时间复杂度:
O(n^2 * log(m))
,n
是A
的长度,m
是两点的最大坐标差值 - 空间复杂度:
O(n)
- 时间复杂度:
# you can write to stdout for debugging purposes, e.g. # print("this is a debug message") # from extratypes import Point2D # library with types used in the task class Point2d: def __init__(self, x, y): self.x = x self.y = y def get_A(li): res = [] for x, y in li: res.append(Point2d(x, y)) return res from collections import defaultdict # find the greatest common divisor def gcd(x, y): if y == 0: return x else: return gcd(y, x % y) def solution(A): # Task: find how many triplets that can form a line # Limit: (1) n <= 10^3, (2) A.x, A.y < 10^4, (4) A is distinct # Method: Hash Map, using gcd to record slopes # Time Complexity: O(n^2 * log(m)), where n is len(A), m is max difference of x coordinates and y coordinates # Space Complxity: O(n) n = len(A) res = 0 # traverse the first point A[i] for i in range(n - 1): x1, y1 = A[i].x, A[i].y # 'slopes' format is like {slope1: num1, slope2: num2, ...} slopes = defaultdict(int) # find the slopes between A[i] and all other later points for j in range(i + 1, n): x2, y2 = A[j].x, A[j].y dx, dy = x2 - x1, y2 - y1 # find the most simple form g = gcd(dx, dy) if g != 0: dx //= g dy //= g # record this slope slopes["{}/{}".format(dy, dx)] += 1 # The result would add C(n, 2) = n * (n-1) // 2 for slope in slopes: res += slopes[slope] * (slopes[slope] - 1) // 2 # Do not exceed the limit if res > 10 ** 8: return -1 return res li = [[1, 1], [0, 0], [2, 2], [3, 2], [4, 2], [3, 3], [5, 1], [4, 4]] res = solution(get_A(li)) print(res)
OK,以上就是本次笔经。笔试结束后就收到收集意向的邮件了,果断选了PM!历尽千帆,还是做PM最快乐。祝愿有面试机会 & 面试顺利!
#微软##校招##笔经#