給定一個已排序的整數集合,找出其中最長等差數列(Longest Arithmetic Progression, LLAP)的長度。等差數列指任意相鄰兩項差值恆定的序列。
輸入: {1, 7, 10, 15, 27, 29} → 輸出: 3 (如 {1, 15, 29}, 公差 14)
輸入: {5, 10, 15, 20, 25, 30} → 輸出: 6 (整個集合即為等差數列)
固定中間元素 set[j],尋找 set[i] (iset[i] + set[k] == 2*set[j]。利用雙指針:
i = j-1, k = j+1i--;過小 → k++;相等 → 找到。j 掃描 O(n),總複雜度 O(n²)。L[i][j] 表示以 set[i] 和 set[j] 為前兩項的最長等差數列長度(j > i)。
L[i][n-1] = 2(任意兩項至少構成長度 2 的 AP)。j 從右向左(n-2 ... 1)填表,確保 L[j][k] 已計算完成。固定 j,雙指針 i=j-1, k=j+1 搜尋:
set[i] + set[k] < 2*set[j] → k++set[i] + set[k] > 2*set[j] → L[i][j] = 2; i--(無法形成更長 AP,基礎長度 2)== → L[i][j] = L[j][k] + 1(延續 j,k 的 AP),更新全域最大值,i--, k++ 繼續找同 j 的其他組合。循環結束後,剩餘 i 設置 L[i][j] = 2。
j + 雙指針掃描)。public class LongestArithmeticProgression {
// 判斷是否存在長度≥3的AP
public static boolean arithmeticThree(int[] A, int n) {
for (int j = 1; j < n-1; ++j) {
int i = j-1, k = j+1;
while (i >= 0 && k <= n-1) {
int sum = A[i] + A[k];
int target = 2 * A[j];
if (sum == target) return true;
else if (sum > target) --i;
else ++k;
}
}
return false;
}
// O(n²) DP 求 LLAP 長度
public static int lengthOfLongestAP(int[] A, int n) {
if (n <= 2) return n;
int[][] L = new int[n][n];
int llap = 2;
for (int i = 0; i < n; ++i) L[i][n-1] = 2; // 最後一列初始化
for (int j = n-2; j >= 1; --j) {
int i = j-1, k = j+1;
while (i >= 0 && k <= n-1) {
int sum = A[i] + A[k];
int target = 2 * A[j];
if (sum < target) ++k;
else if (sum > target) { L[i][j] = 2; --i; }
else {
L[i][j] = L[j][k] + 1;
llap = Math.max(llap, L[i][j]);
--i; ++k;
}
}
while (i >= 0) { L[i][j] = 2; --i; }
}
return llap;
}
public static void main(String[] args) {
int[] A = {1, 7, 10, 15, 27, 29};
System.out.println(arithmeticThree(A, A.length)); // true
System.out.println(lengthOfLongestAP(A, A.length)); // 3
}
}
j 從右向左,保證 L[j][k] 就緒。i 只遞減、k 只遞增,無回溯。n <= 2 直接回傳 n。來源:GeeksforGeeks - Length of LLAP in a sorted array