Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
👉 Mục tiêu: Mỗi ngày giải 1 bài LeetCode, kiên trì tạo thói quen, từng bước chinh phục các kỹ năng lập trình.
Xin chào anh em lập trình viên! Hôm nay mình sẽ deep dive vào một bài toán rất hay về xử lý xâu dấu ngoặc trên LeetCode. Bài này không chỉ kiểm tra tính hợp lệ của xâu dấu ngoặc thông thường, mà còn cho phép ta “hack” một số vị trí! 😎
Đầu tiên, mình sẽ chia sẻ cách tư duy và giải quyết bài toán này một cách chi tiết:
Trước khi bắt đầu code, chúng ta cần hiểu rõ các trường hợp có thể xảy ra:
TEST CASES:
1. s = "(()", locked = "001" -> false (độ dài lẻ)
2. s = "(())", locked = "1111" -> true (đã hợp lệ)
3. s = "))()", locked = "0000" -> true (có thể đổi thành "(())")
4. s = ")(", locked = "11" -> false (không đổi được, bị khóa)
5. s = "())(", locked = "0011" -> true (đổi 2 kí tự đầu)
Time complexity: $$O(n)$$ – một lần duyệt qua xâu
Space complexity: $$O(n)$$ – hai stack trong trường hợp xấu nhất
class Solution {
public:
bool canBeValid(string s, string locked) {
// Bước 1: Check điều kiện cơ bản - độ dài phải chẵn
if (s.length() % 2 != 0) return false;
// Khởi tạo hai stack để theo dõi
stack<int> openStack, freeStack;
// Bước 2: Duyệt từng ký tự trong xâu
for (int i = 0; i < s.length(); i++) {
if (locked[i] == '0') {
// Case 1: Ký tự có thể thay đổi -> lưu vào freeStack
freeStack.push(i);
}
else if (s[i] == '(') {
// Case 2: Dấu mở ngoặc bị khóa -> lưu vào openStack
openStack.push(i);
}
else { // Case 3: s[i] == ')' và bị khóa
// Thử ghép với dấu mở ngoặc gần nhất
if (!openStack.empty()) {
openStack.pop();
}
// Không có '(' -> dùng ký tự tự do
else if (!freeStack.empty()) {
freeStack.pop();
}
// Không có cách nào để ghép -> invalid
else {
return false;
}
}
}
// Bước 3: Xử lý các dấu mở ngoặc còn thừa
while (!openStack.empty() && !freeStack.empty()) {
// Check vị trí: ký tự tự do phải nằm sau dấu mở ngoặc
if (openStack.top() > freeStack.top()) return false;
openStack.pop();
freeStack.pop();
}
// Cuối cùng: nếu còn dấu mở ngoặc -> invalid
return openStack.empty();
}
};
int main() {
Solution sol;
// Test case 1: Có thể biến đổi
cout << "Test 1: " << (sol.canBeValid("())", "010") ? "TRUE" : "FALSE") << endl;
// Kết quả mong đợi: False
// Test case 2: Không thể biến đổi
cout << "Test 2: " << (sol.canBeValid(")(", "11") ? "TRUE" : "FALSE") << endl;
// Kết quả mong đợi: FALSE
// Test case phức tạp
cout << "Test 3: " << (sol.canBeValid("())(())", "0000000") ? "TRUE" : "FALSE") << endl;
// Kết quả mong đợi: TRUE
return 0;
}
Vậy là đã xong Day 3 ae ạ ! Hy vọng bài viết này giúp ích cho anh em! Nếu có thắc mắc gì, comment bên dưới nhé! 🚀
Follow blog của tụi mình để đón những bài viết tiếp theo về thuật toán và competitive programming nhé! Happy coding! 💻✨
Code Editor cho ae test, chạy chơi thôi nha ae =)))
gud, chúc em thành công
Hay qua a