Arithmetic Slices II - Subsequence

Updated on 13 May, 2025
Arithmetic Slices II - Subsequence header image

Problem Statement

In the given task, we are presented with an integer array called nums, and our aim is to determine the total number of subsequences within this array that qualify as arithmetic sequences. To be defined as arithmetic, a series must include at least three numbers where the difference between any successive pairs remains consistent across the sequence.

For instance, sequences such as [1, 3, 5, 7, 9] and [7, 7, 7, 7] meet the criteria as each maintains a fixed difference between elements, whether that difference is positive, negative, or zero. In contrast, a sequence like [1, 1, 2, 5, 7] doesn't qualify due to varying differences between successive values.

Further elaboration includes understanding the concept of a subsequence, which unlike subsequents, allows the exclusion (but not rearrangement) of certain elements from the parent array to form a new sequence. For example, [2,5,10] is a valid subsequence extracted from a larger array [1,2,1,2,4,1,5,10].

Given the constraints specified, the task guarantees that the result will fit within a 32-bit integer, emphasizing efficiency in handling potentially large datasets.

Examples

Example 1

Input:

nums = [2,4,6,8,10]

Output:

7

Explanation:

All arithmetic subsequence slices are:
[2,4,6]
[4,6,8]
[6,8,10]
[2,4,6,8]
[4,6,8,10]
[2,4,6,8,10]
[2,6,10]

Example 2

Input:

nums = [7,7,7,7,7]

Output:

16

Explanation:

Any subsequence of this array is arithmetic.

Constraints

  • 1  <= nums.length <= 1000
  • -231 <= nums[i] <= 231 - 1

Approach and Intuition

To tackle the problem of counting all arithmetic subsequences in the array nums, one can utilize a methodical and analytical approach:

  1. Understand the variable properties of an arithmetic sequence:

    • It must contain no less than three elements.
    • The difference, or common ratio d, between consecutive elements must remain constant.
  2. Conceptually, to identify and count these subsequences, a viable approach is using a dynamic programming technique paired with the utilization of a hashmap or dictionary to keep track of potential arithmetic differences and their frequency at each element in the array.

  3. As you iterate through the array:

    • For each element nums[j], consider it as a possible end element of an arithmetic subsequence.
    • For every preceding element nums[i] where i < j, calculate the difference d = nums[j] - nums[i].
    • Using a hashmap, record how often each difference d occurs up to position j.
    • If a specific difference d has been encountered before at a preceding position, it indicates potential extensions to previous subsequences, contributing to new subsequences ending at j.
  4. Implement a running count of subsequences as you progress through the list which, eventually, when the array is wholly parsed, yields the total count of valid arithmetic subsequences.

By applying this guided approach using dynamic programming concepts paired with effective hash mapping to categorize and count subsequences based on their common ratio of differences, it facilitates an efficient solution to the problem given the constraints outlined.

Solutions

  • C++
  • Java
cpp
#define LONG long long
class Solution {
public:
    int findArithmeticSlices(vector<int>& nums) {
        int length = nums.size();
        LONG total = 0;
        vector<map<LONG, int>> count(length);
        for (int current = 1; current < length; current++) {
            for (int prev = 0; prev < current; prev++) {
                LONG difference = (LONG)nums[current] - (LONG)nums[prev];
                int sequenceCount = 0;
                if (count[prev].find(difference) != count[prev].end()) {
                    sequenceCount = count[prev][difference];
                }
                count[current][difference] += sequenceCount + 1;
                total += sequenceCount;
            }
        }

        return (int)total;
    }
};

The solution is a C++ implementation designed to count the number of subsequences in a given array that form an arithmetic progression. Follow these steps to understand how the provided code achieves this:

  1. Define a type LONG to represent long long for handling large integers and ensuring there is no integer overflow during calculations.

  2. Inside the findArithmeticSlices function, initialize total to track the count of arithmetic subsequences and declare a vector of maps, where each map will store the difference between elements as keys and the count of ways to achieve this difference up to the current index as values.

  3. Use a nested loop where the outer loop variable current moves from the second element to the last element of the input vector nums. The inner loop variable prev counts from starting index to one less than current.

  4. For each pair of current and prev, compute the difference between the nums[current] and nums[prev]. Look up this difference in the map at the prev index to see how often this difference has occurred before current.

  5. If this difference has been seen before prev, the count of these previous occurrences is retrieved and updated in the map at the current index to include these previous subsequences plus the current pair.

  6. Add the count of sequences ending at prev and having the same difference to the overall total, which accumulates the total number of valid arithmetic subsequences.

  7. Finally, the function returns the total as an integer, giving the count of all arithmetic subsequences present in the array, not including sequences shorter than length 3.

This solution effectively uses dynamic programming with a hashmap to efficiently count all subsequences that are arithmetic, ensuring that even if the input grows large, the approach remains efficient in both time and space.

java
class Solution {
    public int countArithmeticSubarrays(int[] nums) {
        int length = nums.length;
        long total = 0;
        Map<Integer, Integer>[] maps = new Map[length];
        for (int i = 0; i < length; i++) {
            maps[i] = new HashMap<>(i);
            for (int j = 0; j < i; j++) {
                long difference = (long)nums[i] - (long)nums[j];
                if (difference < Integer.MIN_VALUE || difference > Integer.MAX_VALUE) {
                    continue;
                }
                int diff = (int)difference;
                int count = maps[j].getOrDefault(diff, 0);
                int currentCount = maps[i].getOrDefault(diff, 0);
                maps[i].put(diff, currentCount + count + 1);
                total += count;
            }
        }
        return (int)total;        
    }
}

The problem focuses on counting the number of arithmetic subsequence slices within a given array using Java. The solution effectively uses dynamic programming coupled with hashing to keep track of the progress.

  • Initialize array maps of HashMaps to store count of possible sequences ending with a specified difference up to the current index.
  • Iterate through each element in the array using two nested loops
    • Calculate the difference between the current pair of indices.
    • Continue to the next iteration if the difference is outside the integer range.
    • Use the difference as a key in the maps for:
      • Keeping track of count of subsequences with this difference up to the current index.
      • Adding this count to the subsequences count of subsequences ending at the next element.
      • Keeping a running total of all valid arithmetic subsequences encountered.
  • Return the total count of arithmetic subsequences found.

The emphasis in the solution is on calculating differences between each pair and leveraging hash maps to store the count of each unique difference, which optimizes the process of identifying valid subsequences. This approach allows handling the comparisons effectively, especially for larger datasets. At the end of the iterations, a cast to int for the total count is required to match the function's signature, ensuring the method returns the correct type.

Comments

No comments yet.