最近,Microsoft 的 Codility OA 正在大量發放中。
很多同學看到題目後的第一反應是:「穩了,這不就是 DP/貪心 嗎?」
千萬別大意。
如果你只把它當成普通的演算法題寫,哪怕 Bug Free,大概率也只能拿個 Rej。
我們 oavoservice 團隊第一時間拿到了真題,發現這裡面埋了無數個 Engineering Judgment(工程判斷力) 的深坑。
🔍 為什麼 Microsoft Codility 的題「陰」?
Microsoft 不像 Google/Meta 那樣喜歡出 LeetCode Hard,但它有個更噁心的特點:
✅ 題目描述很長,業務場景複雜
✅ 需要自己處理輸入輸出
❌ 邊界條件極其刁鑽
❌ DP 狀態定義稍有偏差,全盤皆輸
而且 Codility 平台的特點是:
- 沒有互動式 Debugger
- 提交後才能看到哪些用例掛了
- 一旦 TLE,你根本不知道是哪個用例超時
這種「盲打」模式,對心態的考驗極大。
昨天我們有個 UIUC 的學員,第一題寫了 40 分鐘,提交後發現只過了 60%,當場就慌了。如果不是我們的 Senior 導師實時在語音裡穩住他:「別急,這是 DP 狀態轉移出了問題,重新定義狀態!」,他大概率第二題都寫不完。
最後結果?110分鐘,2道題,全部 All Passed。 穩穩拿下面試門票。
今天把這套熱乎的真題拆解一下,告訴你們坑都在哪。
💻 真題一:多米諾骨牌序列(Domino Sequence)
🔍 題目核心
給定長度為 2*N 的陣列 A,表示 N 個多米諾骨牌。每個骨牌由兩個數字組成:
- 第 K 個骨牌的左右數字分別是
A[2*K]和A[2*K+1]
正確的多米諾序列:相鄰骨牌的接觸部分數字必須相同。
題目要求:最少需要移除多少個骨牌,使剩餘骨牌形成正確序列?
限制:
- 不允許重新排序或旋轉骨牌
- N 範圍:[1..50,000]
- 每個元素範圍:[1..6]
範例解析
Example 1:
A = [2, 4, 1, 3, 4, 6, 2, 4, 1, 6]
骨牌:(2,4), (1,3), (4,6), (2,4), (1,6)
- (2,4) 和 (1,3):右邊 4 != 左邊 1,不連接
- (2,4) 和 (4,6):右邊 4 == 左邊 4,可以連接!
- 最優解:保留 (2,4), (4,6),移除其他 3 個
答案:3
🤯 為什麼這題掛了一大片?
絕大多數人看到這題,第一反應是:
❌ 「這不就是最長連續子序列嗎?」
❌ 「用貪心,能連就連!」
❌ 「暴力列舉所有可能!」
然後越寫越亂,最後發現根本處理不了:
- 如何定義「可連接」?
- 如何處理多個可能的起點?
- 如何保證找到全域最優解?
✅ 正確的工程思維
這是一個**「最長遞增子序列」的變種 + DP」**問題。
關鍵洞察
這不是「貪心」,而是「動態規劃」!
- 每個骨牌都可以作為起點
- 對於每個骨牌,需要找到前面所有能連接的骨牌
- 狀態轉移:
dp[i] = max(dp[j] + 1),其中j < i且骨牌j的右邊等於骨牌i的左邊
💣 隱形坑點
坑點 1:陣列索引轉換
# 錯誤寫法
left = A[i] # ❌ 這是什麼?
# 正確寫法
left = A[2*i] # 第 i 個骨牌的左邊
right = A[2*i + 1] # 第 i 個骨牌的右邊
坑點 2:邊界條件
- 只有 1 個骨牌:答案是 0(不需要移除)
- 所有骨牌都不相連:答案是 N-1(保留任意 1 個)
坑點 3:DP 初始化
- 每個骨牌單獨成序列時,長度都是 1
- 不能初始化為 0
🎯 滿分實作(Python)
def solution(A):
if len(A) == 0:
return 0
n = len(A) // 2
if n == 1:
return 0
# 構建骨牌列表
dominoes = []
for i in range(n):
left = A[2 * i]
right = A[2 * i + 1]
dominoes.append((left, right))
# DP: dp[i] 表示以第 i 個骨牌結尾的最長序列長度
dp = [1] * n
for i in range(1, n):
for j in range(i):
# 如果第 j 個骨牌的右邊等於第 i 個骨牌的左邊
if dominoes[j][1] == dominoes[i][0]:
dp[i] = max(dp[i], dp[j] + 1)
# 最長序列的長度
max_keep = max(dp)
# 需要移除的數量
return n - max_keep
⚡️ 時間複雜度優化
上面的解法是 O(n²),對於 N=50,000 可能會 TLE。
優化思路:用 HashMap 記錄每個右值對應的最長序列
def solution(A):
if len(A) == 0:
return 0
n = len(A) // 2
if n == 1:
return 0
# HashMap: right_value -> max_length
max_len = {}
overall_max = 1
for i in range(n):
left = A[2 * i]
right = A[2 * i + 1]
# 查找能連接到當前骨牌左邊的最長序列
current_len = max_len.get(left, 0) + 1
# 更新以 right 結尾的最長序列
max_len[right] = max(max_len.get(right, 0), current_len)
overall_max = max(overall_max, current_len)
return n - overall_max
時間複雜度:O(n)
空間複雜度:O(1) (因為骨牌數字只有 1-6)
🔢 真題二:三個非相鄰元素的最大和(Maximum Sum of Three Non-Adjacent Elements)
🔍 題目核心
給定整數陣列 A,選擇恰好 3 個非相鄰元素,使其和最大。
非相鄰定義:三個元素的索引必須滿足任意兩個索引的差 > 1。
限制:
- N 範圍:[5..100,000]
- 元素範圍:[-100,000,000..100,000,000]
範例解析
Example 1:
A = [8, -4, -7, -5, -5, -4, 8, 8]
- 位置 0, 3, 6:8 + (-5) + 8 = 11
- 位置 0, 5, 7:8 + (-4) + 8 = 12 ✅ 最優
- 位置 0, 6, 7:8 + 8 + 8 = 24,但 6 和 7 相鄰 ❌
答案:12
Example 2:
A = [-2, -8, 1, 5, -8, 4, 7, 6]
- 位置 3, 5, 7:5 + 4 + 6 = 15 ✅
答案:15
Example 3(負數情況):
A = [-3, 0, -6, -7, -9, -5, -2, -6]
- 位置 1, 3, 6:0 + (-7) + (-2) = -9 ✅
答案:-9
🤯 隱形殺招:為什麼 90% 的人會掛?
看似簡單的題目,實際上有三個致命陷阱:
陷阱 1:暴力列舉會 TLE
# ❌ 這樣寫必掛
max_sum = float('-inf')
for i in range(n):
for j in range(i+2, n):
for k in range(j+2, n):
max_sum = max(max_sum, A[i] + A[j] + A[k])
時間複雜度:O(n³),對於 N=100,000 必然超時。
陷阱 2:貪心選 3 個最大值會錯
# ❌ 錯誤思路
sorted_indices = sorted(range(n), key=lambda i: A[i], reverse=True)
# 然後試圖找 3 個不相鄰的?
反例:
A = [10, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 8]
- 最大的 3 個:10, 9, 8
- 但位置:0, 6, 12
- 0 和 6 相差 6 > 1,6 和 12 相差 6 > 1 ✅
- 看起來可行?但如果是 [10, 1, 9, 1, 8] 呢?
貪心在有負數時完全失效!
陷阱 3:DP 狀態定義不清晰
很多人想用 DP,但不知道狀態怎麼定義:
# ❌ 錯誤狀態
dp[i] = "前 i 個元素的最大和" # 選了幾個?
✅ 正確的工程思維:枚舉中間元素 + 預處理
核心洞察
固定中間元素,問題變簡單!
- 枚舉第二個元素的位置
j(中間那個) - 在
[0, j-2]中找最大值(第一個元素) - 在
[j+2, n-1]中找最大值(第三個元素)
關鍵優化:預處理前綴/後綴最大值
💣 最容易翻車的地方
邊界條件:
- 陣列長度至少為 5(3 個元素 + 2 個間隔)
- 中間元素的範圍:
[2, n-3]
負數處理:
- 不能跳過負數!即使都是負數,也必須選 3 個
🎯 滿分實作(Python)
def solution(A):
n = len(A)
# 邊界檢查
if n < 5:
return float('-inf') # 不可能有解
# 預處理:prefix_max[i] 表示 [0, i] 的最大值
prefix_max = [float('-inf')] * n
prefix_max[0] = A[0]
for i in range(1, n):
prefix_max[i] = max(prefix_max[i-1], A[i])
# 預處理:suffix_max[i] 表示 [i, n-1] 的最大值
suffix_max = [float('-inf')] * n
suffix_max[n-1] = A[n-1]
for i in range(n-2, -1, -1):
suffix_max[i] = max(suffix_max[i+1], A[i])
# 枚舉中間元素
max_sum = float('-inf')
for j in range(2, n-2):
# 第一個元素從 [0, j-2] 中選
first = prefix_max[j-2]
# 第三個元素從 [j+2, n-1] 中選
third = suffix_max[j+2]
current_sum = first + A[j] + third
max_sum = max(max_sum, current_sum)
return max_sum
時間複雜度:O(n)
空間複雜度:O(n)
💡 說句現實的:Microsoft Codility OA,真的不適合裸考
Microsoft SDE 的 TC(北美):
New Grad:$160k – $180k
SDE II:$200k – $250k
而 Codility OA 的殘酷現實是:
❌ 輸入輸出需要自己處理
❌ 沒有互動式除錯
❌ 一個邊界條件錯誤 = 全掛
❌ 一次機會,可能等半年
我們在 oavoservice 做的事情,其實很簡單:
✅ 你寫程式碼
✅ 有人盯狀態定義
✅ 有人盯邊界條件
✅ 有人盯時間複雜度
✅ 在你要 TLE / 寫歪之前,直接叫停
不是你不行,是一個人上場風險太高。
🚀 oavoservice:你的滿分通關專家
面對 Microsoft 這種 工程量大、細節層層遞進 的 Codility OA,你需要的不只是一份答案,而是一個專業的 技術團隊 支援。
我們提供:
✅ Codility 平台全覆蓋:熟悉平台特性,規避隱藏陷阱
✅ 程式碼符合工業級標準:Production-Level Code,不是刷題風格
✅ 實時語音助攻:OA 進行時,資深工程師實時指導
✅ 滿分保障:不過不收費,我們對自己的實力有信心
不要讓一道 DP 狀態轉移、一個邊界條件,卡住你通往 $200k Offer 的路。
我們長期穩定承接各大科技公司如 Microsoft、Google、Amazon 等的 OA 筆試代寫服務,確保滿分通過。
👉 立即添加微信:Coding0201
鎖定你的 Microsoft 面試機會!