Explore all courses in this category.
Explore all courses in this category.
Nguyễn Đình Cường
0 comment
09 Nov, 2026
Trong các buổi phỏng vấn thuật toán, rất nhiều bài thực chất là biến thể của vài mẫu quen thuộc. Học mẫu giúp bạn nhận ra hướng giải nhanh thay vì mò từ đầu. Bài này giới thiệu hai mẫu phổ biến: hai con trỏ và cửa sổ trượt, kèm ví dụ và dấu hiệu nhận biết.
Dùng hai chỉ số cùng di chuyển trên mảng hoặc chuỗi, thường là từ hai đầu tiến vào giữa hoặc cùng đi theo một chiều với tốc độ khác nhau. Mục tiêu là thay vòng lặp lồng nhau O(n²) bằng một lượt duyệt O(n).
function twoSumSorted(nums, target) { let left = 0; let right = nums.length - 1; while (left < right) { const sum = nums[left] + nums[right]; if (sum === target) return [left, right]; if (sum < target) left++; else right--; } return null;}console.log(twoSumSorted([1, 3, 4, 6, 9], 10)); // [0, 4]Vì mảng đã sắp xếp, nếu tổng nhỏ hơn mục tiêu thì cần số lớn hơn nên tăng left; nếu lớn hơn thì giảm right. Mỗi bước loại bỏ ít nhất một ứng viên nên tổng cộng O(n) thời gian và O(1) bộ nhớ.
function removeDuplicates(nums) { if (nums.length === 0) return 0; let write = 1; for (let read = 1; read < nums.length; read++) { if (nums[read] !== nums[read - 1]) { nums[write] = nums[read]; write++; } } return write; // số phần tử khác nhau}Con trỏ read quét toàn bộ mảng còn write đánh dấu vị trí ghi tiếp theo. Đây là biến thể hai con trỏ cùng chiều (còn gọi là nhanh và chậm).
Duy trì một đoạn liên tiếp (cửa sổ) của mảng hoặc chuỗi, mở rộng bên phải và thu hẹp bên trái, thay vì tính lại toàn bộ đoạn mỗi lần.
function maxSumK(nums, k) { if (nums.length < k) return null; let sum = 0; for (let i = 0; i < k; i++) sum += nums[i]; let best = sum; for (let i = k; i < nums.length; i++) { sum += nums[i] - nums[i - k]; best = Math.max(best, sum); } return best;}console.log(maxSumK([2, 1, 5, 1, 3, 2], 3)); // 9Thay vì cộng lại k số mỗi lần (O(n·k)), ta cộng số mới vào và trừ số vừa rời cửa sổ, nên chỉ O(n).
function longestUnique(s) { const seen = new Set(); let left = 0; let best = 0; for (let right = 0; right < s.length; right++) { while (seen.has(s[right])) { seen.delete(s[left]); left++; } seen.add(s[right]); best = Math.max(best, right - left + 1); } return best;}console.log(longestUnique('abcabcbb')); // 3Cửa sổ [left, right] luôn không chứa ký tự trùng. Khi gặp ký tự trùng, ta thu hẹp bên trái cho đến khi hợp lệ. Mỗi ký tự được thêm và xóa tối đa một lần nên độ phức tạp là O(n).
| Tình huống | Mẫu gợi ý |
|---|---|
| Tìm cặp trong mảng đã sắp xếp | Hai con trỏ hai đầu |
| Kiểm tra đối xứng | Hai con trỏ hai đầu |
| Đoạn con liên tiếp có điều kiện | Cửa sổ trượt |
| Sửa mảng tại chỗ | Hai con trỏ cùng chiều |
Nhận ra mẫu là kỹ năng luyện được. Hãy giải khoảng năm đến mười bài cho mỗi mẫu, và sau mỗi bài ghi lại dấu hiệu giúp bạn nhận ra mẫu đó. Sau một thời gian, bạn sẽ thấy các bài lạ trở nên quen thuộc hơn nhiều.
Nếu bạn muốn học thuật toán theo lộ trình có bài tập, hãy xem thêm các khóa học tại codebem.com.
Nguyễn Đình Cường
0 comment