Patterns/Part VIII - Cross-Topic Deep Dives/Arithmetic DP

Pattern Reference

Arithmetic DP

"DP on arithmetic properties. Sum of digits, divisibility, carry DP, digit DP variants with arithmetic constraints."

Loading...

Deep Dive Tutorial

For longest arithmetic subsequence: dp[i] is a map from difference d to the length of the longest AP ending at arr[i] with difference d. For each i, j < i: d = arr[i] - arr[j]; dp[i][d] = max(dp[i][d], (dp[j][d] ?? 1) + 1). The answer is the maximum value across all dp[i] maps. O(n²) time with hashmaps for differences.

Arithmetic progression DP templates
// Longest arithmetic subsequence
function longestArithSeqLength(nums) {
    const n = nums.length;
    const dp = Array.from({length: n}, () => new Map());
    let ans = 2;
    for (let i = 1; i < n; i++) {
        for (let j = 0; j < i; j++) {
            const d = nums[i] - nums[j];
            const len = (dp[j].get(d) ?? 1) + 1;
            dp[i].set(d, Math.max(dp[i].get(d) ?? 2, len));
            ans = Math.max(ans, dp[i].get(d));
        }
    }
    return ans;
}

// Count arithmetic slices (subarrays) with at least 3 elements
function countArithSlices(nums) {
    const n = nums.length;
    let total = 0, cur = 0;
    for (let i = 2; i < n; i++) {
        if (nums[i] - nums[i-1] === nums[i-1] - nums[i-2]) {
            cur++;
            total += cur;
        } else {
            cur = 0;
        }
    }
    return total;
}

// Count arithmetic subsequences (not just subarrays)
function countArithSeqSubseq(nums) {
    const MOD = 1e9 + 7;
    const n = nums.length;
    const dp = Array.from({length: n}, () => new Map());
    let total = 0;
    for (let i = 1; i < n; i++) {
        for (let j = 0; j < i; j++) {
            const d = nums[i] - nums[j];
            const prevLen = dp[j].get(d) ?? 0;
            const newLen = prevLen + 1;
            dp[i].set(d, (dp[i].get(d) ?? 0) + newLen);
            total += prevLen; // count subsequences of length >= 3
        }
    }
    return total % MOD;
}

Worked Problems

triangle
AP DP state space:
- dp[i][d] = AP length ending at index i with difference d
- Transitions: O(n) per index, n indices → O(n²) total
- Space: O(n²) in worst case (all different differences), but often sparse

Subarrays vs subsequences:
- Subarrays: O(n) with running count (simple)
- Subsequences: O(n²) with hashmaps

Fixed difference: O(n) with a single hashmap dp[value] = longest AP ending at this value.

Optimization for counting: dp stores (partial APs of length ≥ 2) that can be extended. When we extend them to length 3, they contribute to the count.