Đích đến không phải là một con số bài
Một người đã bấm “Accepted” 400 lần vẫn có thể đứng hình khi đề thay bối cảnh. Ngược lại, người hiểu sâu khoảng một trăm bài đại diện có thể nhận ra cấu trúc chung và chuyển nó sang bài mới. Vì vậy câu hỏi “cần giải bao nhiêu bài?” chỉ có ích sau khi xác định chất lượng của một vòng học.
Mỗi bài nên tạo ra bốn sản phẩm: lời giải đúng, lời giải thích bằng lời, một ghi chú về tín hiệu nhận dạng và một lịch ôn lại. Nếu chỉ lưu code, bạn đang luyện gõ. Phỏng vấn đánh giá cả cách làm rõ yêu cầu, chọn phương án, kiểm ca biên và giao tiếp khi chưa có đáp án hoàn chỉnh.
Trong 12 tuần, hãy ưu tiên độ phủ của các mẫu quan trọng và khả năng giải thích, không chạy theo chuỗi ngày hay tổng số bài. Một bài được chữa kỹ có giá trị hơn năm bài đọc đáp án rồi chép lại.
Tuần 1–2: dựng nền và quy trình nói
Hai tuần đầu tập trung mảng, xâu, bảng băm và bài toán Two Sum, sắp xếp, hai con trỏ và tìm kiếm nhị phân. Mục tiêu không phải bài khó mà là quy trình ổn định. Với mỗi đề, hãy nói lại input, output, ràng buộc; hỏi về giá trị trùng, mảng rỗng, tràn số; đưa ra vét cạn trước rồi mới tối ưu.
Ví dụ tìm vị trí đầu tiên của x trong mảng đã sắp. Tín hiệu là “đã sắp” và “đầu tiên”, nên dùng biên trái thay vì dừng ở lần tìm thấy bất kỳ. Bất biến của đoạn [l,r) là mọi vị trí trước l nhỏ hơn x, còn mọi vị trí từ r trở đi đều lớn hơn hoặc bằng x; vì vậy đáp án luôn nằm trong [l, r]. Với [1,2,2,2,5], x=2, các đoạn lần lượt co từ [0,5) thành [0,2), [0,1), rồi trả 1.
#include <iostream>
#include <vector>
using namespace std;
int first_pos(const vector<long long>& a, long long x) {
int l = 0, r = (int)a.size();
while (l < r) {
int m = l + (r - l) / 2;
if (a[m] >= x) {
r = m;
} else {
l = m + 1;
}
}
return (l < (int)a.size() && a[l] == x) ? l : -1;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
long long x;
if (!(cin >> n >> x)) return 0;
vector<long long> a(n);
for (auto& v : a) cin >> v;
cout << first_pos(a, x) << '\n';
return 0;
}
import sys
def first_pos(a: list[int], x: int) -> int:
l, r = 0, len(a)
while l < r:
m = l + (r - l) // 2
if a[m] >= x:
r = m
else:
l = m + 1
return l if l < len(a) and a[l] == x else -1
def main() -> None:
data = list(map(int, sys.stdin.buffer.read().split()))
if len(data) < 2:
return
x = data[1]
a = data[2:]
print(first_pos(a, x))
if __name__ == "__main__":
main()
import java.util.*;
public class Main {
static int firstPos(long[] a, long x) {
int l = 0, r = a.length;
while (l < r) {
int m = l + (r - l) / 2;
if (a[m] >= x) {
r = m;
} else {
l = m + 1;
}
}
return (l < a.length && a[l] == x) ? l : -1;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
if (!sc.hasNextInt()) return;
int n = sc.nextInt();
long x = sc.nextLong();
long[] a = new long[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextLong();
}
System.out.println(firstPos(a, x));
}
}
Đoạn code ngắn nhưng luyện được ba điều phỏng vấn hay kiểm: chọn mô hình nửa mở, tránh tràn ở trung điểm và xác minh sau vòng lặp. Hãy tự đổi yêu cầu thành “vị trí cuối cùng” hoặc “vị trí chèn” để biết mình hiểu bất biến chứ không thuộc mẫu.
Tuần 3–5: cấu trúc dữ liệu và mẫu tuyến tính
Chuyển sang stack, queue, linked list với con trỏ nhanh chậm (Fast & Slow Pointers), mẫu Top K phần tử bằng Heap, mẫu cửa sổ trượt trong phỏng vấn, mảng cộng dồn tiền tố và bài toán gộp các khoảng thời gian (Merge Intervals) trong hệ thống 14 dạng bài LeetCode hay gặp nhất. Mỗi ngày chỉ nên có một mẫu chính: một bài dễ để nhắc cơ chế, một hoặc hai bài vừa để biến đổi. Sau khi giải, ghi câu “khi nào không dùng”: cửa sổ trượt thường cần một điều kiện có thể phục hồi bằng cách dịch biên; heap không thay cho sắp xếp nếu cần toàn bộ thứ tự; bảng băm không giữ thứ tự nếu đặc tả thư viện không cam kết điều đó.
Một buổi 90 phút có thể chia thành 10 phút đọc và hỏi, 25 phút tự giải, 20 phút cài đặt, 15 phút chạy tay, 20 phút chữa. Nếu hết 25 phút mà chưa có hướng, xem một gợi ý nhỏ thay vì đọc toàn bộ lời giải. Sau đó đóng tài liệu và tự viết lại từ đầu. Việc bí có kiểm soát là dữ liệu để điều chỉnh lộ trình, không phải thất bại.
| Dấu hiệu trong đề | Mẫu nên nghĩ tới | Câu tự hỏi trước code |
|---|---|---|
| cặp phần tử đạt tổng | bảng băm / hai con trỏ | cần chỉ số hay chỉ cần tồn tại? |
| đoạn liên tiếp thỏa điều kiện | cửa sổ trượt / tiền tố | điều kiện có đơn điệu khi dịch biên? |
| phần tử lớn nhất liên tục | heap | có cập nhật hay chỉ lấy một lần? |
| dấu ngoặc hoặc “gần nhất chưa ghép” | stack | phần tử trên đỉnh đại diện điều gì? |
Tuần 6–8: cây, đồ thị và quay lui
Học DFS/BFS qua bài toán số hòn đảo (Number of Islands), duyệt cây nhị phân theo từng tầng bằng BFS, kiểm tra cây tìm kiếm nhị phân hợp lệ, sắp xếp topo trong bài toán lịch học (Course Schedule), cấu trúc tập hợp rời rạc và mẫu quay lui sinh tập con, tổ hợp. Đừng nhớ code bằng hình dạng; hãy nói được trạng thái và thời điểm đánh dấu. BFS đánh dấu khi đưa vào hàng đợi để mỗi đỉnh vào một lần. DFS trên đồ thị cần mảng đánh dấu đã thăm, còn DFS trên cây có thể truyền đỉnh cha. Quay lui phải trả trạng thái về đúng trước khi thử nhánh kế tiếp.
Ở giai đoạn này, luyện vẽ rất quan trọng. Vẽ năm đỉnh, mô phỏng queue hoặc stack, ghi màu chưa thăm/đang thăm/đã xong. Khi đề hỏi đường đi ngắn trên đồ thị không trọng số, bạn phải giải thích vì sao lớp BFS đầu tiên chạm đích là ngắn nhất. Khi đề hỏi thứ tự phụ thuộc, hãy nêu cách phát hiện chu trình chứ không chỉ in ra một danh sách.
Tuần 9–10: quy hoạch động có công thức
DP chỉ nên bắt đầu sau khi bạn viết được trạng thái bằng một câu. Ví dụ dp[i] là đáp án tốt nhất dùng i phần tử đầu, không phải “mảng dp”. Sau đó xác định lựa chọn cuối, điều kiện gốc và thứ tự tính. Luyện các dạng Dynamic Programming thường gặp khi phỏng vấn gồm một chiều, lưới, chuỗi, cái túi; đặt hai bài gần nhau để nhận ra phần giống và phần thay đổi.
Nếu một lời giải top-down chạy đúng, hãy thử chuyển sang bottom-up và nén bộ nhớ. Nhưng không nén trước khi hiểu phụ thuộc. Trong phỏng vấn, phiên bản rõ ràng O(n) bộ nhớ thường tốt hơn bản O(1) khó giải thích nếu ràng buộc chưa ép. Tối ưu là một quyết định có lý do, không phải phản xạ trình diễn.
Tuần 11–12: mô phỏng phỏng vấn và vá lỗ hổng
Mỗi tuần làm ít nhất hai phiên 45 phút: không autocomplete, không xem gợi ý, nói thành tiếng và để năm phút cuối tự kiểm. Trộn chủ đề để tránh nhận dạng bằng tên chương. Sau phiên, chấm theo bốn cột: làm rõ đề, hướng giải, độ đúng code, giao tiếp. Một lỗi lặp lại ba lần phải trở thành mục tiêu học tuần sau.
Bài hướng dẫn phỏng vấn chung của Grow with Google khuyên nghiên cứu vai trò, chuẩn bị ví dụ từ kinh nghiệm và luyện trả lời có cấu trúc. Lời khuyên đó áp dụng rộng hơn việc giải thuật: đừng dành toàn bộ ba tháng cho code rồi bỏ trống phần câu hỏi tình huống làm việc, dự án và câu hỏi dành cho người phỏng vấn. Bạn có thể xem chi tiết cách chuẩn bị cho từng định dạng ở bài phỏng vấn Google Software Engineer, phỏng vấn Amazon SDE và Leadership Principles, cùng cách phân bổ thời gian trong vòng Meta Online Assessment.
Bảng theo dõi có ý nghĩa
Đừng chỉ ghi Accepted. Mỗi hàng nên có ngày, mẫu, thời gian nghĩ, số lần cần gợi ý, lỗi chính và ngày ôn lại. Dùng ba mức: xanh nếu tự giải và giải thích được; vàng nếu cần gợi ý; đỏ nếu chưa dựng được trạng thái. Ôn đỏ sau 24 giờ, vàng sau ba ngày, xanh sau một hoặc hai tuần.
Sau mỗi 20 bài, chọn ngẫu nhiên ba bài cũ và giải lại không nhìn code. Nếu không nhận ra, vấn đề là lưu giữ chứ không phải thiếu bài mới. Nếu nhận ra nhưng code sai biên, thêm bảng ca biên. Nếu code đúng nhưng nói rối, thu âm phần trình bày hai phút rồi sửa.
Những cách học khiến số bài tăng nhưng năng lực đứng yên
- Đọc lời giải quá sớm và tự nhủ “mình cũng nghĩ vậy”. Hãy viết lại sau khi đóng tài liệu.
- Chỉ làm một chủ đề liên tục đến mức tên chương tiết lộ thuật toán. Hãy trộn đề ở giai đoạn ôn.
- Không chạy tay ca nhỏ, nên lỗi chỉ số lặp lại ở tìm kiếm nhị phân và cửa sổ trượt.
- Tối ưu ngay từ đầu, bỏ qua vét cạn nên không có đối chứng và khó giải thích bước tiến hóa.
- Bỏ Java hoặc ngôn ngữ sẽ dùng trong phỏng vấn đến tuần cuối. Hãy chọn một ngôn ngữ chính sớm.
Một tuần mẫu có thể lặp lại
Thứ hai học một mẫu mới bằng một bài cơ chế và tự viết ghi chú. Thứ ba giải hai biến thể, trong đó bài thứ hai không ghi tên chủ đề. Thứ tư ôn hai bài cũ và dành 30 phút cho câu hỏi tình huống hoặc dự án. Thứ năm làm một bài có giới hạn thời gian; thứ sáu chữa lỗi và viết lại code sạch. Cuối tuần thực hiện một buổi phỏng vấn thử 45 phút, rồi nghỉ đủ để tuần sau không bắt đầu trong trạng thái kiệt sức.
Mỗi ngày không nhất thiết kéo dài nhiều giờ. Một phiên 60–90 phút tập trung thường tốt hơn ba giờ vừa xem lời giải vừa nhắn tin. Nếu đi làm toàn thời gian, có thể dùng bốn ngày ngắn và một buổi cuối tuần. Lịch tốt là lịch bạn giữ được mười hai tuần, không phải lịch đẹp nhất trên bảng tính.
| Ngày | Việc chính | Sản phẩm phải lưu |
|---|---|---|
| thứ hai | học mẫu mới | bất biến và một phản ví dụ |
| thứ ba | hai biến thể | so sánh điểm giống/khác |
| thứ tư | ôn xen kẽ | lỗi nhớ sai và ca biên |
| thứ năm | bài bấm giờ | mốc thời gian từng giai đoạn |
| thứ sáu | chữa sâu | bản viết lại không nhìn đáp án |
| cuối tuần | phỏng vấn thử + tổng kết | hai thay đổi cho tuần tới |
Thang chấm một bài thay vì chỉ Accepted
Chấm mỗi tiêu chí 0–2. Làm rõ: có hỏi ràng buộc và đặc tả hàm không? Mô hình: có nêu vét cạn, nút thắt và bất biến không? Cài đặt: code có đúng, dễ đọc, không dựa vào khuôn mẫu mù không? Kiểm thử: có ca phá các nhánh chính không? Giao tiếp: người nghe có theo được quyết định không? Tổng điểm thấp ở đâu thì kế hoạch tuần sau tập trung ở đó.
Một bài đạt sau ba lần sai không phải vô giá trị; lỗi chính là dữ liệu. Hãy phân loại: hiểu sai đề, chọn sai thuật toán, điều kiện biên, cài đặt, ngôn ngữ hay quản lý thời gian. Nếu cùng loại lặp ba lần, ngừng lấy bài mới và thiết kế một buổi sửa riêng.
Cách chữa một bài đã xem lời giải
Đầu tiên đóng lời giải và viết lại ý tưởng bằng ba câu. Sau đó dựng code từ đầu, không sao chép. Tiếp theo tạo một biến thể: đổi đầu ra từ kiểm tra tồn tại sang đếm số cách, cho phép cập nhật, hoặc yêu cầu truy vết. Cuối cùng giải lại sau 24 giờ. Nếu chỉ nhớ từng dòng mà không giải thích được bất biến, bài chưa hoàn thành.
Với tìm kiếm nhị phân biên trái, biến thể có thể là lower_bound, upper_bound, đếm số phần tử bằng x và tìm kiếm nhị phân trên không gian đáp án. Với BFS, biến thể là loang từ nhiều nguồn hoặc dựng lại đường đi. Một mẫu chỉ trở thành kỹ năng khi bạn biết phần nào giữ nguyên và phần nào phải đổi.
Điều chỉnh lộ trình theo vai trò mục tiêu
Vị trí phát triển phía máy chủ (backend) có thể cần thêm cơ sở dữ liệu, xử lý đồng thời và thiết kế hệ thống; di động (mobile) cần vòng đời ứng dụng, mạng và nền tảng; dữ liệu (data) cần SQL, thống kê và đường ống xử lý; nhúng (embedded) cần bộ nhớ, thao tác bit, C/C++ và hệ điều hành. Lộ trình Coding Interview 150 tạo nền tảng giải thuật nhưng không thay thế mô tả công việc. Mỗi tuần dành ít nhất một phiên cho năng lực ngoài LeetCode mà vị trí ứng tuyển ghi rõ.
Ứng viên mới nên giữ dự án và kiến thức nền song song theo 10 kỹ năng lập trình viên cần có. Ứng viên có kinh nghiệm cần chuẩn bị câu chuyện về trách nhiệm đầu-cuối, sự đánh đổi kỹ thuật, hệ thống đã vận hành, hiểu rõ AI đang thay đổi công việc kỹ sư phần mềm ra sao và biết cách đọc báo cáo mức lương lập trình viên tại Việt Nam để định vị hồ sơ khi nhận đề nghị tuyển dụng. Nếu lịch phỏng vấn gần, ưu tiên lỗ hổng có xác suất cao và khả năng sửa; không cố nhồi toàn bộ khoa học máy tính trong vài ngày.
Khi nào nên giảm hoặc tăng độ khó
Nếu ba bài mức trung bình liên tiếp cần lời giải đầy đủ, hạ một bậc và quay lại cơ chế. Nếu bạn giải bài mức trung bình dưới 20 phút nhưng không thể giải thích, giữ độ khó và luyện nói. Nếu cả code lẫn giải thích đều ổn trong nhiều buổi, thêm biến thể hoặc bài ghép hai mẫu. Bài mức khó (Hard) chỉ có ích khi nó tạo kỹ năng mới, không phải để trang trí thống kê.
Theo dõi sức khỏe nhận thức. Dấu hiệu quá tải là đọc cùng một dòng nhiều lần, lỗi cú pháp bất thường và không nhớ bài hôm qua. Nghỉ, ngủ và vận động không nằm ngoài lộ trình; chúng quyết định khả năng học và thể hiện trong ngày phỏng vấn.
Bài kiểm tra cuối mỗi giai đoạn
Cuối tuần 2, tự cài bảng băm, hai con trỏ và tìm kiếm nhị phân không nhìn mẫu. Cuối tuần 5, làm một buổi tập phỏng vấn thử trộn mảng, cửa sổ trượt, ngăn xếp hoặc heap. Cuối tuần 8, mô phỏng cây/đồ thị và giải thích mảng đánh dấu. Cuối tuần 10, viết trạng thái quy hoạch động từ ba đề nhưng chỉ cài đặt một đề. Cuối tuần 12, làm phiên đầy đủ gồm giải thuật và câu hỏi tình huống làm việc.
Tiêu chuẩn qua giai đoạn không phải 100% đúng lần đầu. Hãy yêu cầu: nhận ra hướng tiếp cận trong vài phút, nêu được sự đánh đổi kỹ thuật, cài đặt một phương án đúng trong thời gian hợp lý và tự tìm phần lớn lỗi bằng ca biên. Phần chưa đạt đi vào danh sách ôn sau, không bị che bằng số bài mới.
Luyện ngay trên Big-O Coding
Bắt đầu bằng ba bài đại diện rồi đi tiếp theo thứ tự của lộ trình Coding Interview 150.
Câu hỏi thường gặp
Ba tháng có đủ không?
Đủ để tạo nền có cấu trúc nếu bạn đã biết một ngôn ngữ và học đều. Kế hoạch 3 tháng của Tech Interview Handbook tính khoảng 11 giờ mỗi tuần; học ít hơn thì kéo dài lịch. Nếu mới lập trình, hãy kéo dài lịch thay vì bỏ qua nền tảng.
Có cần làm bài Hard không?
Không phải ưu tiên đầu. Hãy chắc bài Easy/Medium đại diện, rồi chọn Hard để luyện ghép nhiều ý khi vị trí mục tiêu thực sự cần.
Nên dùng C++, Python hay Java?
Dùng ngôn ngữ bạn viết đúng và giải thích thư viện rõ nhất. Tập với đúng phiên bản và môi trường gần buổi phỏng vấn.
Luyện LeetCode thực chiến theo pattern, giải bài trong 45 phút và mock interview cùng AI. 16 buổi online, lớp 7–12 học viên, chọn C++, Java hoặc Python.


