Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
👋 Chào mừng mọi người quay trở lại với Learning AI with Losers! Hôm nay, chúng ta sẽ tiếp tục Day 31 của series Leetcode Daily Challenge với một bài toán thú vị: “Đếm số lượng cặp tệ (bad pairs)”.
Trước khi bắt tay vào giải quyết bài toán, hãy cùng tưởng tượng một chút nhé!
🖼 Minh họa trực quan:
Hãy tưởng tượng bạn đang xếp những viên bi theo hàng ngang. Nếu một viên bi đáng lẽ phải nằm ở vị trí phù hợp nhưng lại lệch đi so với quy luật, chúng ta sẽ gọi đó là một bad pair.
Bạn được cung cấp một mảng số nguyên có chỉ mục bắt đầu từ 0 là nums
. Một cặp chỉ mục (i, j)
được gọi là “bad pair” nếu i < j
và j - i != nums[j] - nums[i]
.
Trả về tổng số "bad pairs" trong nums
.
Ví dụ 1:
Input: nums = [4,1,3,3] Output: 5 Giải thích: Cặp (0, 1) là bad pair vì 1 - 0 != 1 - 4. Cặp (0, 2) là bad pair vì 2 - 0 != 3 - 4, 2 != -1. Cặp (0, 3) là bad pair vì 3 - 0 != 3 - 4, 3 != -1. Cặp (1, 2) là bad pair vì 2 - 1 != 3 - 1, 1 != 2. Cặp (2, 3) là bad pair vì 3 - 2 != 3 - 3, 1 != 0. Tổng cộng có 5 bad pairs, vì vậy trả về 5.
Ví dụ 2:
Input: nums = [1,2,3,4,5] Output: 0 Giải thích: Không có bad pairs nào.
Ràng buộc:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9
Bạn được cho một mảng số nguyên nums
được đánh chỉ số từ 0. Một cặp chỉ số (i, j) được gọi là cặp xấu (bad pair) nếu thỏa mãn:
Nói cách khác, một cặp được coi là "xấu" khi độ chênh lệch giữa các vị trí (j - i) không bằng độ chênh lệch giữa các giá trị tại những vị trí đó (nums[j] - nums[i]).
Ví dụ cho dễ hiểu:
nums = [4,1,3,3] Xét cặp (0,1): - j - i = 1 - 0 = 1 - nums[j] - nums[i] = nums[1] - nums[0] = 1 - 4 = -3 Do 1 ≠ -3 nên (0,1) là một cặp xấu
Hay nói cách khác, nếu sự chênh lệch về chỉ số không khớp với sự chênh lệch về giá trị thì cặp đó là một bad pair.
🔹 Input: nums = [4,1,3,3]
🔹 Output: 5
🔹 Giải thích:
Cặp (i, j) | j−ij - i | nums[j]−nums[i]nums[j] - nums[i] | Bad Pair? |
---|---|---|---|
(0, 1) | 1 | -3 | ✅ |
(0, 2) | 2 | -1 | ✅ |
(0, 3) | 3 | -1 | ✅ |
(1, 2) | 1 | 2 | ✅ |
(2, 3) | 1 | 0 | ✅ |
Tổng cộng có 5 bad pairs.
🔹 Input: nums = [1,2,3,4,5]
🔹 Output: 0
🔹 Giải thích: Không có bad pairs vì mọi phần tử đều tuân theo quy luật.
Bài toán yêu cầu đếm số lượng bad pairs, nhưng kiểm tra từng cặp (i, j) bằng cách duyệt brute-force sẽ tốn O(n²), quá chậm với n ≤ 10⁵.
Ta có thể biến đổi điều kiện:
j - i ≠ nums[j] - nums[i]
Suy ra:
nums[j] - j ≠ nums[i] - i
Hay nói cách khác, ta sẽ kiểm tra sự khác biệt giữa giá trị và chỉ số.
Nếu có nhiều phần tử có cùng giá trị nums[i] - i, thì chúng sẽ tạo thành good pairs.
Cuối cùng, số lượng bad pairs sẽ là:
total pairs - good pairs
nums = [4,1,3,3]
i | nums[i] | nums[i] - i | Tần suất |
---|---|---|---|
0 | 4 | 4 | 1 |
1 | 1 | 0 | 1 |
2 | 3 | 1 | 1 |
3 | 3 | 0 | 2 |
(4 * (4 - 1)) / 2 = 6
C(2,2) = 1
6 - 1 = 5 ✅
O(n)
, vì chỉ duyệt mảng một lần và sử dụng hash map.O(n)
, vì cần lưu hash map.class Solution {
public:
long long combinations(int n) {
return 1LL * n * (n - 1) / 2;
}
long long countBadPairs(vector<int>& nums) {
map<int, int> number_to_freq;
long long cnt_good_pairs = 0;
for (int i = 0; i < nums.size(); i++) {
number_to_freq[nums[i] - i] += 1;
}
for (auto it : number_to_freq) {
if (it.second > 1) {
cnt_good_pairs += combinations(it.second);
}
}
return combinations(nums.size()) - cnt_good_pairs;
}
};
Hãy tưởng tượng các phần tử trong nums
như các điểm trên một đồ thị.
📌 Nếu ta vẽ các điểm (i, nums[i])
, thì các điểm có cùng giá trị nums[i] - i
sẽ nằm trên cùng một đường thẳng!
Ví dụ, với nums = [4,1,3,3]
:
nums[i] - i
= 0 xuất hiện 2 lần, tạo ra 1 good pair.🖼 Hình minh họa:
Index: 0 1 2 3
Nums: 4 1 3 3
Diff: 4 0 1 0
👀 Các phần tử có diff = 0
tạo thành good pairs, còn lại là bad pairs.
🔥 Đây là một bài toán thú vị với cách tiếp cận hash map + toán học giúp giảm độ phức tạp từ O(n²) ➝ O(n)!
📌 Những điều quan trọng rút ra từ bài này:
✅ Biến đổi điều kiện bài toán để nhận ra các phần tử giống nhau có thể nhóm lại.
✅ Sử dụng hash map để đếm nhanh số lần xuất hiện.
✅ Hiểu công thức tổ hợp giúp tính nhanh số lượng cặp có thể có.
📝 Bạn có thể áp dụng kỹ thuật này cho nhiều bài toán liên quan đến counting pairs!
💬 Bạn có thích cách tiếp cận này không? Hãy để lại bình luận nhé! 🚀
📌 Hashtags:
#leetcode #leetcodedaily #coding #datastructures #algorithms #learningwithlosers