Cho mảng A gồm N số. Một dãy con (subsequence) là dãy chỉ số (K0, K1, ..., Kn) với 0 ≤ K0 < K1 < ... < Kn < N. Dãy con gọi là dãy cộng dồn nếu các giá trị A[K0], A[K1], ..., A[Kn] tạo thành cấp số cộng (chênh lệch giữa các phần tử liên tiếp bằng nhau) và n ≥ 2 (ít nhất 3 phần tử).
Ví dụ
A = [2, 4, 6, 8, 10] → có 7 dãy cộng dồn:
- Độ dài 3:
[2,4,6], [2,4,10], [4,6,8], [6,8,10] - Độ dài 4:
[2,4,6,8], [4,6,8,10] - Độ dài 5:
[2,4,6,8,10]
Thuật toán: DP với Hash Map
dp[i][diff] = số dãy cộng dồn kết thúc tại chỉ số i với công sai diff (có độ dài ≥ 2).
- Duyệt cặp
(j, i)vớij < i. diff = A[i] - A[j].- Số dãy kết thúc ở
jvới công saidifflàtemp = dp[j][diff](mặc định 0). - Cộng
tempvào kết quả (vì mỗi dãy đó mở rộng thêmA[i]thành dãy độ dài ≥ 3). - Nếu
A[i] + difftồn tại trong mảng (có thể mở rộng tiếp), cập nhậtdp[i][diff] += temp + 1(+1 cho cặp(j, i)mới).
Cài đặt C++
#include <bits/stdc++.h>
using namespace std;
typedef long long int lli;
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
int ret = 0;
unordered_map<lli, unordered_map<lli, lli>> dp;
unordered_set<int> s(A.begin(), A.end());
int n = A.size();
for (int i = 1; i < n; i++) {
for (int j = i - 1; j >= 0; j--) {
lli diff = (lli)A[i] - (lli)A[j];
if (diff <= INT_MIN || diff > INT_MAX) continue;
int temp = dp[j].count(diff) ? dp[j][diff] : 0;
ret += temp;
if (s.count(A[i] + diff)) dp[i][diff] += temp + 1;
}
}
return ret;
}
};
int main() {
Solution ob;
vector<int> v = {2, 4, 6, 8, 10};
cout << ob.numberOfArithmeticSlices(v);
return 0;
}
Độ phức tạp
- Thời gian:
O(n^2)— duyệt tất cả cặp(j, i). - Không gian:
O(n^2)— lưudpcho mỗi cặp(i, diff).
Input / Output
Input: {2,4,6,8,10}
Output: 7