Nội dung
Danh sách bài học
- 01~22 phút
Độ phức tạp Big-O từ bản chất — Theta, Omega, amortized intro
Big-O không chỉ là ký hiệu — đó là công cụ dự đoán hành vi thuật toán ở quy mô lớn. Bài này giải thích tại sao bỏ constants, phân biệt O / Theta / Omega, 7 complexity class với Java 21, và những pitfall khiến code O(n log n) chạy chậm hơn O(n²).
- 02~20 phút
Recursion & call stack — Khi đệ quy phá vỡ JVM
Đệ quy trông gọn về lý thuyết nhưng ẩn một nguy cơ thực sự trong production: StackOverflowError. Bài này giải thích cơ chế call stack trên JVM, tại sao JVM không có tail-call optimization, và khi nào nên chuyển từ đệ quy sang iteration.
- 03~20 phút
Amortized analysis — Vì sao ArrayList.add() là O(1) dù đôi khi tốn O(n)
ArrayList.add() được document là O(1) amortized — nhưng đôi khi nó tốn O(n). Bài này giải thích amortized từ bản chất: 3 phương pháp phân tích, lý do 1.5x growth factor được chọn, và khi nào amortized cứu bạn — khi nào nó lừa bạn.
- 04~22 phút
Memory model & cache locality — Vì sao LinkedList chậm hơn int[] 25 lần
Cùng O(n) nhưng int[] nhanh hơn LinkedList<Integer> 25 lần khi sum 10 triệu phần tử. Bài này giải thích cache locality từ bản chất: CPU memory hierarchy, cache line, object layout trong JVM, và khi nào Big-O không đủ để dự đoán hiệu năng thực tế.
- 05~18 phút
Framework giải bài thuật toán — 5 bước biến brute force thành tối ưu
Gặp bài toán mới mà đầu óc trống rỗng? Bài này dạy framework 5 bước biến mọi bài toán — kể cả bài chưa từng gặp — thành approach có thể code được, kèm complexity guarantee.
- 06~30 phút
Mini-challenge — findCommonElements: naive vs optimized
Bài thực hành khép lại Module 1 — viết findCommonElements hai cách (nested loop vs HashSet), đo benchmark nanoTime, và nhận ra vì sao 8 giây xuống còn 30ms.
- 07~28 phút
Case Study: ArrayList.grow() — Vì sao 1.5x là magic number
Stack Overflow hỏi: Java ArrayList dùng 1.5x grow factor, C++ std::vector dùng 2x — Oracle chọn sai? Bài này đọc thẳng OpenJDK 21 source, đo benchmark, và phân tích 3 góc kỹ thuật để trả lời câu hỏi đó.