Tác giả: Nguyễn RR Thành Trung

Mở đầu

Bạn đã bao giờ bước vào một cuộc phỏng vấn mà không biết phải chuẩn bị gì? Bạn đã bao giờ phỏng vấn xong, nghĩ mình trả lời cũng ổn, nhưng vẫn bị đánh trượt? Trong bài viết này, mình muốn chia sẻ về việc phỏng vấn từ góc nhìn của người phía bên kia chiến tuyến.

Ở Garena Singapore, mình được làm nhiệm vụ phỏng vấn các ứng viên nộp đơn vào vị trí Software Engineer.

Quy trình phỏng vấn của Garena có thể nói là khá đơn giản, sau khi hồ sơ qua được vòng duyệt hồ sơ, thí sinh phải trải qua:

  • 2 vòng phỏng vấn kiến thức cơ bản trong khoa học máy tính như thuật toán, kĩ năng code, hệ điều hành, mạng máy tính, database, ...
    • Trong thời gian mình làm ở Garena, công ty có phỏng vấn rất nhiều người từ Việt Nam qua. Mình thường sẽ phỏng vấn những thí sinh này qua Skype bằng tiếng Việt. Vòng còn lại sẽ phỏng vấn bằng tiếng Anh. Quan điểm của công ty mình là kiến thức và kĩ năng quan trọng hơn ngôn ngữ, nên tiếng Anh của bạn kém 1 chút cũng không sao (miễn có thể hiểu nhau là được). Điều này hoàn toàn khác với một số công ty như Google.
    • Vì phỏng vấn qua Skype, thí sinh ngồi phỏng vấn qua máy tính, và code luôn trực tiếp qua online editor.
  • Nếu vị trí có tính chất đặc biệt như lập trình Android / iOS, frontend, thì thí sinh sẽ phải trải qua thêm 1 vòng phỏng vấn nữa, hỏi chuyên sâu về kiến thức cần biết của vị trí đó.

Chú ý rằng trong bài viết này, mình chỉ chia sẻ quan điểm của cá nhân mình về việc phỏng vấn. Nó không phản ánh quan điểm của Garena và có thể không đúng nếu bạn phỏng vấn Garena với một người phỏng vấn khác.

Mục đích phỏng vấn

Theo quan điểm của mình, một cuộc phỏng vấn là một cuộc tìm hiểu lẫn nhau của ứng viên và công ty:

  • Trong suốt quá trình phỏng vấn, người phỏng vấn sẽ cố gắng tìm hiểu kiến thức, kĩ năng cũng như tính cách của bạn, để xem có phù hợp với công ty hay không. Dù bạn có giỏi nhưng tính cách không phù hợp thì cũng chắc chắn không được nhận.
  • Ngược lại, là ứng viên, bạn cũng cần tìm hiểu công ty. Mình thường đánh giá rất thấp những ứng viên chỉ biết trả lời những gì được hỏi, và không có chút gì muốn tìm hiểu về công ty.

Nội dung phỏng vấn

Như đã nói ở trên, nội dung phỏng vấn gồm rất nhiều phần:

  • Thuật toán
  • Kĩ năng code
  • Hệ điều hành
  • Mạng máy tính
  • Database

Tùy theo người phỏng vấn, họ sẽ hỏi các phần ở các độ sâu khác nhau, tuy nhiên thuật toán và kĩ năng code thường là phần quan trọng nhất. Cá nhân mình thì chỉ giỏi về thuật toán và code, nên mình thường chỉ hỏi tập trung vào 2 phần đó, và các phần khác mình thường hỏi khá đơn giản.

Thuật toán và Kĩ năng code

Thông thường, với câu hỏi về thuật toán, mình sẽ nhìn vào Resume của ứng viên để chọn câu hỏi. Thường sau khi nhìn hồ sơ mình chia thành 3 nhóm:

  1. Nhóm chưa từng tham gia Competitive Programming
  2. Nhóm đã từng tham gia Competitive Programming: đã từng thi những giải như HSG cấp tỉnh, quốc gia hoặc Tin học trẻ
  3. Nhóm có rất nhiều kinh nghiệm Competitive Programming: thường là mình đã từng nghe tên hoặc đã biết.

Với 3 nhóm, độ khó câu hỏi cũng như yêu cầu của mình sẽ khác nhau.

Ai + Aj = S

Với nhóm 1 và 2 (và thỉnh thoảng là nhóm 3), mình hỏi cùng 1 câu hỏi như sau:

Cho mảng A gồm N phần tử và một số nguyên S. Đếm số cặp chỉ số (i, j) mà A(i) + A(j) = S Ví dụ: A = [1, 5, 2, 4, 3] S = 6 --> code của bạn cần trả lại 2

Sau khi nghe xong câu hỏi thì thường bạn sẽ phải nói cho mình cách làm, sau khi mình thấy hợp lý thì bạn có thể bắt đầu code. Mình chọn câu hỏi này vì nó có nhiều cách làm:

1. Cách $O(N^2)$

Cách hiển nhiên nhất $O(N^2)$: Dùng 2 vòng for để đếm. Đây là cách cơ bản nhất và ứng viên buộc phải trả lời được. Cài đặt cũng rất đơn giản như sau:

int result = 0;
for (int i = 0; i < n; i++)
  for (int j = i + 1; j < n; j++)
    if (A[i] + A[j] == S)
      result += 1;

Chú ý vòng for bên trong chạy từ i+1 để tránh đếm trùng. Điều này tưởng như rất đơn giản nhưng nhiều thí sinh thuộc nhóm 1 không làm được (các bạn thường for từ 0 và không xử lý được khi thấy đếm bị trùng).

2. Cách $O(N * logN)$

Một cách cài đặt "trâu bò" hơn là $O(N * logN)$:

Sắp xếp lại rồi với mỗi $A_i$, chặt nhị phân để đếm số lượng giá trị $j$. Cách này có nhược điểm là dễ bị đếm trùng. Để khắc phục thì có 2 cách:

  • Chặt nhị phân 2 lần, lần đầu tìm vị trí đầu tiên của $j$, lần 2 tìm vị trí cuối cùng của $j$.
  • Rời rạc hóa.

Mình nhận thấy 1 số bạn trong nhóm 2 đi theo hướng này, nhưng mình không đánh giá cao vì nó phức tạp hơn cách 3 ở dưới. Nhưng tất nhiên nếu bạn cài đặt tốt và đơn giản thì không sao cả.

Khi ứng viên trả lời theo hướng này, thường (tùy theo cảm hứng của mình lúc phỏng vấn), mình có thể hỏi thêm:

  • Bạn biết những thuật toán sort nào?
  • Ngôn ngữ lập trình bạn đang dùng cài đặt thuật toán sort nào?
  • Bạn có thể tự cài đặt 1 thuật toán sort với độ phức tạp $O(N * logN)$ không?

3. Cách $O(N)$

Cách "chuẩn" $O(N)$ là sử dụng hash table hoặc map trong C++ để lưu lại các phần tử của dãy, vừa lưu vừa đếm:

map<int,int> count;
int result = 0;
for (int i = 0; i < n; i++) {
  result += count[S - a[i]];
  count[a[i]] += 1;
}

Thường nếu các bạn chỉ nghĩ ra cách 1, sau khi bạn cài đặt xong, nếu thấy còn đủ thời gian mình sẽ gợi ý để làm được cách này.

Nếu ứng viên trả lời theo hướng này, mình cũng có thể hỏi thêm:

  • Bạn có biết hash table được cài đặt thế nào không?
  • Bạn có thể tự cài đặt hash table không?

Đánh giá

Khi ứng viên trả lời, mình đánh giá theo nhiều tiêu chí:

  • Giải thích thuật toán: Bạn có diễn đạt cho mình hiểu được không?
  • Cẩn thận: Bạn có tránh được các trường hợp lỗi không (chẳng hạn nếu làm theo cách 2 thì dễ bị đếm lặp và bạn có nhận ra không?).
  • Cài đặt: Cách cài đặt của bạn có dễ hiểu không? Có xét đủ hết các trường hợp hay không?
  • Debug: Sau khi code xong bạn có thể chạy thử code của mình. Nếu code sai, mình sẽ quan sát xem bạn debug như nào? Kĩ năng debug có tốt không?

Mình dùng đi dùng lại 1 câu hỏi vì như vậy mình sẽ nắm được rất rõ các cách trả lời khác nhau và các lỗi bạn đã gặp phải. Tuy nhiên tùy ngẫu hứng mình sẽ có thể hỏi thêm các chi tiết khác nhau, ví dụ:

  • Nếu bạn dùng C++: Nếu dùng hàm sort, bạn có biết sort của C++ dùng thuật toán gì không? Nếu dùng vector, bạn có biết độ phức tạp mỗi thao tác là bao nhiêu không?
  • Nếu bạn dùng Python: Bạn có biết trong Python 2 có hàm rangexrange không? Bạn có biết nó khác gì nhau không?

Thường những câu hỏi này mình hỏi khá ngẫu hứng và trong trường hợp không trả lời được, bạn cũng không cần lo lắng.

Count Palindrome

Với nhóm 3, thường mình sẽ hỏi câu như sau:

Cho 1 xâu S. Đếm số substring của S là Palindrome

Bài này cũng có 2 cách làm chính với độ phức tạp $O(N^2)$:

  1. Quy hoạch động
  2. Xét tâm của Palindrome và duyệt sang 2 bên.

Thỉnh thoảng, với nhóm 1 hoặc 2, nếu bạn trả lời câu trước quá kém và mình thấy còn thời gian, mình sẽ cho "gỡ gạc" bằng câu này, tuy nhiên mình chỉ yêu cầu làm cách duyệt toàn bộ với độ phức tạp $O(N^3)$ là đủ.

Đánh giá của mình cũng dựa trên những tiêu chí như phần trên.

Hệ điều hành

Phần này mình thường không hỏi nhiều. Mình thường sẽ bắt đầu bằng câu hỏi:

Thread và Process giống và khác nhau thế nào?

Sau đó, tùy theo cách bạn trả lời hoặc tâm trạng của mình lúc đó, mình có thể hỏi thêm 1 số phần khác như:

  • Thread Communication và Process Communication
  • Lock, Semaphore
  • Context Switch

Mình không giỏi về hệ điều hành nên thường yêu cầu không cao. Bạn trả lời được những ý cơ bản là đạt yêu cầu của mình.

Mạng máy tính

Phần này mình cũng thường không hỏi nhiều. Mình thường bắt đầu bằng câu hỏi:

UDP và TCP khác nhau thế nào?

Sau đó, mình có thể hỏi thêm 1 số phần khác như:

  • TCP handshake
  • Congestion control

Mình không giỏi về phần nên thường yêu cầu không cao. Bạn trả lời được những ý cơ bản là đạt yêu cầu của mình.

Những lỗi cần tránh

Ở Garena mình được đánh giá là một trong những người phỏng vấn khó tính nhất. Với những người khó tính như mình, có một số lỗi mà bạn cần tránh trong suốt quá trình phỏng vấn:

  • Dùng Google mà không nói với mình: Mình đã từng gặp trường hợp sau khi mình vừa nói câu hỏi, thí sinh xin phép suy nghĩ nhưng sau đó mình lại nghe thấy nhiều tiếng gõ phím và click chuột (chú ý mình phỏng vấn qua Skype nên mới có trường hợp như vậy). Mình đoán bạn đó đang Google để tìm lời giải, và trường hợp như vậy gần như chắc chắn sẽ bị đánh trượt.
  • Đến muộn lúc phỏng vấn: Nếu bạn vào muộn không quá 5 phút thì thường mình cũng không có vấn đề gì, tuy nhiên nếu bạn đến quá muộn mà không có lý do phù hợp thì mình sẽ đánh giá là bạn không có sự chuẩn bị cẩn thận cho cuộc phỏng vấn.
  • Chém gió quá nhiều trong Resume: Nếu bạn viết bất kỳ cái gì vào Resume, mình có thể sẽ hỏi. Nếu bạn không trả lời được những kiến thức cơ bản, mình sẽ đánh giá rất thấp. Ví dụ bạn viết vào Resume là biết dùng git, nhưng không thể giải thích được git commit là gì.
  • Xin đổi câu hỏi với câu thuật toán / code: Đã có trường hợp sau khi mình nói đề, thí sinh không suy nghĩ nhiều mà xin đổi câu hỏi luôn. Vì thuật toán và kỹ năng code là câu hỏi quan trọng, nên thông thường mình sẽ đổi câu hỏi khó hơn.
  • Thể hiện không có tinh thần học hỏi. Ví dụ ứng viên không muốn học ngôn ngữ lập trình mới. Đối với Software Engineer mình thấy đây là điều tối kị, vì công nghệ thay đổi liên tục mỗi ngày và bạn phải không ngừng học hỏi. Ngược lại, cũng đã có trường hợp mình đánh đỗ ứng viên vì mình thấy bạn đó có tinh thần học hỏi rất tốt mặc dù kiến thức không tốt lắm.

Feedback

Thông thường, các công ty sẽ hạn chế đưa ra Feedback đối với thí sinh. Thông thường nếu bạn hỏi sẽ chỉ nhận được những câu trả lời chung chung và hầu hết công ty sẽ không đưa ra lý do chính xác khiến bạn bị đánh trượt. Lý do là để bảo vệ công ty:

  • Nếu không cẩn thận trong việc đưa ra lý do, công ty có thể bị ném đá nếu bạn chia sẻ bừa bãi lý do và lý do đó không được số đông đồng tình.
  • Lý do bạn bị trượt là do người phỏng vấn và có thể là thêm người review lại feedback của người phỏng vấn. Lý do đó có thể không áp dụng cho toàn bộ các cuộc phỏng vấn của công ty và do đó không thể phản ánh đúng về công ty.