Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Xin chào các bạn, Loser1 từ Learning AI with Loser đây! Hôm nay chúng ta tiếp tục series Leetcode Daily Challenge với Day 38. Cùng nhau phân tích một bài toán thú vị về chuỗi số nhé! 🚀
Cho một số nguyên dương n
, hãy tìm một dãy số thỏa mãn tất cả các điều kiện sau:
1
xuất hiện đúng một lần trong dãy.2
đến n
xuất hiện đúng hai lần trong dãy.i
(từ 2
đến n
), khoảng cách giữa hai lần xuất hiện của i
phải bằng chính i
.
Khoảng cách giữa hai số trong dãy, a[i]
và a[j]
, được định nghĩa là giá trị tuyệt đối của hiệu chỉ số của chúng, tức là |j - i|
.
Trả về dãy số có thứ tự từ điển lớn nhất. Đảm bảo rằng với các ràng buộc đã cho, luôn tồn tại một nghiệm.
Một dãy số a
được coi là có thứ tự từ điển lớn hơn dãy số b
(cùng độ dài) nếu tại vị trí đầu tiên mà a
và b
khác nhau, dãy a
có giá trị lớn hơn dãy b
. Ví dụ, [0,1,9,0]
có thứ tự từ điển lớn hơn [0,1,5,6]
vì vị trí đầu tiên chúng khác nhau là vị trí thứ ba, và 9 > 5
.
Example 1:
Input: n = 3 Output: [3,1,2,3,2] Giải thích: [2,3,2,1,3] cũng là một dãy hợp lệ, nhưng [3,1,2,3,2] là dãy có thứ tự từ điển lớn nhất.
Example 2:
Input: n = 5 Output: [5,3,1,4,3,5,2,4,2]
Ràng buộc:
1 <= n <= 20
Thống kê:
Cho một số nguyên n, tìm một chuỗi thỏa mãn các điều kiện sau:
Trả về chuỗi lớn nhất theo thứ tự từ điển. Luôn tồn tại ít nhất một lời giải cho bài toán này.
Ví dụ:
Khi tôi nhìn bài toán này, điều đầu tiên tôi nghĩ đến là: "Hmm, mình cần xây dựng một chuỗi với các ràng buộc phức tạp và tìm chuỗi lớn nhất có thể". Đây rõ ràng là một bài toán tổ hợp, và backtracking là một phương pháp tự nhiên để thử các khả năng khác nhau.
Ý tưởng cơ bản là:
🧩 → 🔍 → 🔄 → ✅
seq
có độ dài 2n-1 (vì số 1 xuất hiện 1 lần, mỗi số từ 2 đến n xuất hiện 2 lần)used
để đánh dấu những số đã được sử dụng[0,0,0,0,0] → [3,0,0,3,0] → [3,1,0,3,0] → [3,1,2,3,2] ✓
seq
có độ dài 2n-1 và mảng used
có độ dài n+1 📦#include <vector>
using namespace std;
class Solution {
public:
int n;
// used[i] = true nếu số i đã được sử dụng (đã đặt đầy đủ các lần xuất hiện của i)
vector<bool> used;
// Hàm đệ quy backtracking: pos là chỉ số hiện tại cần điền trong seq
bool backtrack(vector<int>& seq, int pos) {
// Nếu đã điền hết các vị trí trong seq, trả về true
if(pos == seq.size())
return true;
// Nếu vị trí hiện tại đã có số, chuyển sang vị trí tiếp theo
if(seq[pos] != 0)
return backtrack(seq, pos + 1);
// Duyệt các số từ n xuống 1 để đảm bảo tính lexicographically largest
for (int i = n; i >= 1; i--) {
if(used[i]) continue; // bỏ qua nếu số i đã được đặt
// Nếu i == 1, chỉ cần đặt một lần duy nhất
if(i == 1) {
seq[pos] = 1;
used[1] = true;
if(backtrack(seq, pos + 1))
return true;
// Backtrack
seq[pos] = 0;
used[1] = false;
}
// Với i >= 2, cần đặt hai lần và khoảng cách giữa hai lần xuất hiện phải đúng bằng i
else {
// Kiểm tra xem vị trí thứ hai có hợp lệ không
if(pos + i < seq.size() && seq[pos + i] == 0) {
seq[pos] = i;
seq[pos + i] = i;
used[i] = true;
if(backtrack(seq, pos + 1))
return true;
// Nếu không thành công, quay lại trạng thái ban đầu (backtrack)
seq[pos] = 0;
seq[pos + i] = 0;
used[i] = false;
}
}
}
return false;
}
vector<int> constructDistancedSequence(int n) {
this->n = n;
// Độ dài dãy: 2 * n - 1, vì số 1 xuất hiện 1 lần và các số từ 2 đến n xuất hiện 2 lần
int len = 2 * n - 1;
vector<int> seq(len, 0);
used.assign(n + 1, false);
backtrack(seq, 0);
return seq;
}
};
Hãy cùng nhau theo dõi cách thuật toán hoạt động với n=3:
Kết quả cuối cùng: [3,1,2,3,2] 🎯
Bước 1: [0,0,0,0,0]
Bước 2: [3,0,0,3,0]
Bước 3: [3,1,0,3,0]
Bước 4: [3,1,2,3,2]
Bài toán này là một ví dụ điển hình của kỹ thuật backtracking trong lập trình. Chúng ta xây dựng chuỗi từng bước một, luôn ưu tiên các số lớn trước để đảm bảo tính "lexicographically largest".
Điểm mấu chốt là phải hiểu rõ các ràng buộc của bài toán và cách áp dụng chúng trong quá trình backtracking. Việc luôn thử các số từ lớn đến nhỏ đảm bảo chúng ta sẽ tìm được chuỗi lớn nhất có thể.
🔑 Tóm tắt thuật toán:
Backtracking 101:
📝 Thử từng khả năng
🔍 Kiểm tra tính hợp lệ
🔄 Quay lui nếu không thành công
✅ Lưu lại kết quả khi tìm thấy
Các bạn thấy bài toán này thế nào? Hãy để lại comment chia sẻ suy nghĩ của mình nhé! 💬
Hẹn gặp lại các bạn trong bài tiếp theo của series Leetcode Daily Challenge! 📚
Loser1 from Learning AI with Loser 🚀
CODE EDITOR
📌 Hashtags:
#leetcode #leetcodedaily #coding #datastructures #algorithms #learningwithlosers #leetcode 3066 # leetcodedaily38