Bài toán
Một cụm từ là Palindrome nếu sau khi chuyển tất cả chữ cái in hoa thành in thường và xóa bỏ các ký tự không phải chữ-số (non-alphanumeric), nó đọc xuôi hay đọc ngược đều giống nhau.
Cho một chuỗi s, trả về true nếu nó là Palindrome, ngược lại false.
Ví dụ:
text:
Input: s = "A man, a plan, a canal: Panama"
Output: true
Giải thích: "amanaplanacanalpanama" là chuỗi đối xứng.Phân Tích & Tiếp Cận
Cách 1: Reverse String
- Làm sạch chuỗi (xóa ký tự đặc biệt, lowercase).
- Tạo chuỗi đảo ngược.
- So sánh chuỗi sạch và chuỗi đảo ngược.
typescript:
function isPalindrome(s: string): boolean {
const cleanStr = s.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
const reverseStr = cleanStr.split('').reverse().join('');
return cleanStr === reverseStr;
}- Time Complexity: $O(n)$
- Space Complexity: $O(n)$ (Tạo chuỗi mới).
Cách 2: Two Pointers (Tối ưu bộ nhớ)
Ta không cần tạo chuỗi mới. Ta dùng 2 con trỏ:
leftbắt đầu từ đầu chuỗi (0).rightbắt đầu từ cuối chuỗi (len - 1).
Di chuyển chúng dần vào giữa:
- Nếu
s[left]không phải chữ/số ->left++. - Nếu
s[right]không phải chữ/số ->right--. - Nếu cả 2 đều là chữ/số:
- So sánh
s[left].toLowerCase()vớis[right].toLowerCase(). - Khác nhau ->
return false. - Giống nhau ->
left++,right--.
- So sánh
typescript:
function isPalindrome(s: string): boolean {
let l = 0;
let r = s.length - 1;
while (l < r) {
// Bỏ qua ký tự không phải chữ/số
while (l < r && !isAlphaNumeric(s[l])) {
l++;
}
while (r > l && !isAlphaNumeric(s[r])) {
r--;
}
if (s[l].toLowerCase() !== s[r].toLowerCase()) {
return false;
}
l++;
r--;
}
return true;
}
// Helper check ký tự
function isAlphaNumeric(char: string): boolean {
const code = char.charCodeAt(0);
return (
(code >= 48 && code <= 57) || // 0-9
(code >= 65 && code <= 90) || // A-Z
(code >= 97 && code <= 122) // a-z
);
}- Time Complexity: $O(n)$ - Duyệt mỗi ký tự tối đa 1 lần.
- Space Complexity: $O(1)$ - Không tạo chuỗi hay cấu trúc dữ liệu mới.
Pattern Nhận Diện
Two Pointers (Đối nghịch): Khi cần so sánh hoặc thao tác các phần tử ở hai đầu mảng/chuỗi và di chuyển dần vào giữa. Ứng dụng: Kiểm tra đối xứng, Đảo ngược chuỗi, Tìm cặp số trong mảng đã sắp xếp.