Facebook Pixel

2367. Number of Arithmetic Triplets

EasyArrayHash TableTwo PointersEnumeration
Leetcode Link

Problem Description

You are given an array nums that contains integers in strictly increasing order (each element is larger than the previous one) and a positive integer diff. Your task is to find all arithmetic triplets in the array.

An arithmetic triplet consists of three indices (i, j, k) that satisfy these conditions:

  • The indices must be in order: i < j < k
  • The difference between the elements at positions j and i equals diff: nums[j] - nums[i] == diff
  • The difference between the elements at positions k and j also equals diff: nums[k] - nums[j] == diff

In other words, you need to find three elements in the array that form an arithmetic sequence with a common difference of diff.

For example, if nums = [0, 1, 4, 6, 7, 10] and diff = 3, then (0, 4, 7) forms an arithmetic triplet because:

  • The indices satisfy 0 < 2 < 4 (where nums[0] = 0, nums[2] = 4, nums[4] = 7)
  • 4 - 0 = 4 and 7 - 4 = 3 (wait, this should be nums[1] = 1, nums[2] = 4, nums[4] = 7 with differences 4 - 1 = 3 and 7 - 4 = 3)

The solution uses the combinations function from Python's itertools to generate all possible triplets of three elements from the array, then checks each triplet to see if the differences between consecutive elements equal diff. The sum function counts how many triplets satisfy the conditions.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

Since we need to find triplets where consecutive elements have the same difference diff, we can think of this as finding three numbers that form an arithmetic progression.

The key insight is that the array is strictly increasing, which means we don't have to worry about duplicate values or the order of elements - the natural order of the array already gives us the i < j < k relationship.

Given the small constraint on the array size (at most 200 elements), we can afford to check all possible combinations of three elements. This leads us to a straightforward brute force approach: pick every possible combination of three elements and check if they satisfy our arithmetic progression condition.

For any three elements a, b, c picked in order from the array, they form an arithmetic triplet if b - a == diff and c - b == diff. This is equivalent to saying the middle element is exactly diff away from the first element, and the third element is exactly diff away from the middle element.

The Python combinations function naturally handles generating all possible triplets while maintaining the order, making the implementation clean and concise. We simply count how many of these triplets satisfy both difference conditions using a generator expression inside sum().

This approach works well because:

  1. The array size is small enough that checking all C(n, 3) combinations is feasible
  2. The strictly increasing property ensures no duplicates and maintains order
  3. We only need to verify two simple arithmetic conditions for each triplet

Learn more about Two Pointers patterns.

Solution Approach

The solution uses a brute force approach to enumerate all possible triplets and check if they form arithmetic progressions.

Implementation Details:

  1. Generate all triplets: We use Python's combinations(nums, 3) function to generate all possible combinations of 3 elements from the array. This function automatically maintains the relative order of elements, ensuring that for any triplet (a, b, c), their indices satisfy i < j < k where a = nums[i], b = nums[j], and c = nums[k].

  2. Check arithmetic progression condition: For each triplet (a, b, c), we verify if:

    • b - a == diff (first difference equals diff)
    • c - b == diff (second difference equals diff)

    Both conditions must be true for the triplet to be considered arithmetic.

  3. Count valid triplets: The solution uses a generator expression inside the sum() function. For each triplet, the expression b - a == diff and c - b == diff evaluates to True (which equals 1) if both conditions are met, or False (which equals 0) otherwise. The sum() function adds up all these boolean values, effectively counting the number of valid arithmetic triplets.

Time Complexity: O(nΒ³) where n is the length of the array, since we examine all combinations of 3 elements from n elements, which gives us C(n, 3) = n Γ— (n-1) Γ— (n-2) / 6 combinations.

Space Complexity: O(1) as we only use a constant amount of extra space (the generator doesn't create all combinations at once in memory).

The elegance of this solution lies in its simplicity - by leveraging Python's built-in combinations function and boolean arithmetic, the entire solution fits in a single line while remaining readable and efficient for the given constraints.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a concrete example with nums = [3, 7, 8, 11, 15, 18] and diff = 4.

Step 1: Generate all possible triplets

Using combinations(nums, 3), we get all possible combinations of 3 elements:

  • (3, 7, 8): Check if 7-3=4 and 8-7=1 β†’ No (second difference is 1, not 4)
  • (3, 7, 11): Check if 7-3=4 and 11-7=4 β†’ Yes! Both differences equal 4
  • (3, 7, 15): Check if 7-3=4 and 15-7=8 β†’ No (second difference is 8, not 4)
  • (3, 7, 18): Check if 7-3=4 and 18-7=11 β†’ No
  • (3, 8, 11): Check if 8-3=5 and 11-8=3 β†’ No (first difference is 5, not 4)
  • (3, 8, 15): Check if 8-3=5 and 15-8=7 β†’ No
  • (3, 8, 18): Check if 8-3=5 and 18-8=10 β†’ No
  • (3, 11, 15): Check if 11-3=8 and 15-11=4 β†’ No (first difference is 8, not 4)
  • (3, 11, 18): Check if 11-3=8 and 18-11=7 β†’ No
  • (3, 15, 18): Check if 15-3=12 and 18-15=3 β†’ No
  • (7, 8, 11): Check if 8-7=1 and 11-8=3 β†’ No
  • (7, 8, 15): Check if 8-7=1 and 15-8=7 β†’ No
  • (7, 8, 18): Check if 8-7=1 and 18-8=10 β†’ No
  • (7, 11, 15): Check if 11-7=4 and 15-11=4 β†’ Yes! Both differences equal 4
  • (7, 11, 18): Check if 11-7=4 and 18-11=7 β†’ No (second difference is 7, not 4)
  • (7, 15, 18): Check if 15-7=8 and 18-15=3 β†’ No
  • (8, 11, 15): Check if 11-8=3 and 15-11=4 β†’ No (first difference is 3, not 4)
  • (8, 11, 18): Check if 11-8=3 and 18-11=7 β†’ No
  • (8, 15, 18): Check if 15-8=7 and 18-15=3 β†’ No
  • (11, 15, 18): Check if 15-11=4 and 18-15=3 β†’ No (second difference is 3, not 4)

Step 2: Count valid triplets

We found 2 valid arithmetic triplets:

  1. (3, 7, 11) forms the arithmetic sequence 3 β†’ 7 β†’ 11 with common difference 4
  2. (7, 11, 15) forms the arithmetic sequence 7 β†’ 11 β†’ 15 with common difference 4

Step 3: Return the count

The function returns 2, which is the total number of arithmetic triplets found.

The solution efficiently handles this by using the expression:

sum(b - a == diff and c - b == diff for a, b, c in combinations(nums, 3))

Each valid triplet contributes 1 (True) to the sum, while invalid triplets contribute 0 (False), giving us the final count of 2.

Solution Implementation

1from typing import List
2from itertools import combinations
3
4class Solution:
5    def arithmeticTriplets(self, nums: List[int], diff: int) -> int:
6        """
7        Count the number of arithmetic triplets in the array.
8      
9        An arithmetic triplet is a tuple (i, j, k) where:
10        - i < j < k
11        - nums[j] - nums[i] == diff
12        - nums[k] - nums[j] == diff
13      
14        Args:
15            nums: A sorted array of distinct integers
16            diff: The common difference for arithmetic triplets
17          
18        Returns:
19            The number of arithmetic triplets found
20        """
21        # Use combinations to generate all possible triplets maintaining order
22        # For each triplet (a, b, c), check if they form an arithmetic sequence
23        # with the given difference
24        count = sum(
25            b - a == diff and c - b == diff  # Check if consecutive differences equal 'diff'
26            for a, b, c in combinations(nums, 3)  # Generate all 3-element combinations
27        )
28      
29        return count
30
1class Solution {
2    /**
3     * Counts the number of arithmetic triplets in a strictly increasing array.
4     * An arithmetic triplet is a set of three indices (i, j, k) where:
5     * - i < j < k
6     * - nums[j] - nums[i] == diff
7     * - nums[k] - nums[j] == diff
8     * 
9     * @param nums A strictly increasing integer array
10     * @param diff The common difference for arithmetic triplets
11     * @return The number of arithmetic triplets found
12     */
13    public int arithmeticTriplets(int[] nums, int diff) {
14        int count = 0;
15        int arrayLength = nums.length;
16      
17        // Iterate through all possible first elements of triplets
18        for (int i = 0; i < arrayLength; i++) {
19            // Iterate through all possible second elements after index i
20            for (int j = i + 1; j < arrayLength; j++) {
21                // Iterate through all possible third elements after index j
22                for (int k = j + 1; k < arrayLength; k++) {
23                    // Check if the three elements form an arithmetic triplet
24                    // with the specified difference
25                    if (nums[j] - nums[i] == diff && nums[k] - nums[j] == diff) {
26                        count++;
27                    }
28                }
29            }
30        }
31      
32        return count;
33    }
34}
35
1class Solution {
2public:
3    int arithmeticTriplets(vector<int>& nums, int diff) {
4        int count = 0;  // Counter for valid arithmetic triplets
5        int size = nums.size();  // Store array size to avoid repeated calls
6      
7        // Iterate through all possible starting positions for triplet
8        for (int i = 0; i < size; ++i) {
9            // Second element must come after the first
10            for (int j = i + 1; j < size; ++j) {
11                // Third element must come after the second
12                for (int k = j + 1; k < size; ++k) {
13                    // Check if the three elements form an arithmetic sequence
14                    // with the given difference
15                    if (nums[j] - nums[i] == diff && nums[k] - nums[j] == diff) {
16                        ++count;  // Found a valid triplet
17                    }
18                }
19            }
20        }
21      
22        return count;  // Return total number of arithmetic triplets found
23    }
24};
25
1/**
2 * Counts the number of arithmetic triplets in a strictly increasing array
3 * An arithmetic triplet is a set of three indices (i, j, k) where:
4 * - i < j < k
5 * - nums[j] - nums[i] == diff
6 * - nums[k] - nums[j] == diff
7 * 
8 * @param nums - A strictly increasing array of integers
9 * @param diff - The common difference for arithmetic triplets
10 * @returns The number of arithmetic triplets found
11 */
12function arithmeticTriplets(nums: number[], diff: number): number {
13    const arrayLength: number = nums.length;
14    let tripletCount: number = 0;
15  
16    // Iterate through all possible first elements of triplets
17    for (let i = 0; i < arrayLength; ++i) {
18        // Iterate through all possible middle elements of triplets
19        for (let j = i + 1; j < arrayLength; ++j) {
20            // Iterate through all possible last elements of triplets
21            for (let k = j + 1; k < arrayLength; ++k) {
22                // Check if the three elements form an arithmetic triplet
23                // Both differences must equal the target difference
24                if (nums[j] - nums[i] === diff && nums[k] - nums[j] === diff) {
25                    ++tripletCount;
26                }
27            }
28        }
29    }
30  
31    return tripletCount;
32}
33

Time and Space Complexity

The time complexity is O(n^3), where n is the length of the array nums. This is because the combinations(nums, 3) function generates all possible combinations of 3 elements from the array, which results in C(n, 3) = n! / (3! * (n-3)!) = n * (n-1) * (n-2) / 6 combinations. This simplifies to O(n^3) in Big O notation. For each combination, the code performs constant-time operations (two subtractions and two comparisons), which doesn't change the overall cubic time complexity.

The space complexity is O(1). While the combinations function creates an iterator that generates triplets one at a time, it doesn't store all combinations in memory simultaneously. The generator yields each triplet on demand, and the sum function only keeps track of a single counter variable. Therefore, the space used remains constant regardless of the input size.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Inefficiency with Large Arrays

The brute force approach with O(nΒ³) time complexity becomes inefficient when dealing with large arrays. Since we're checking all possible triplets, this can lead to timeout issues on platforms with strict time limits.

Solution: Use a hash set for O(n) lookup to check if required elements exist:

def arithmeticTriplets(self, nums: List[int], diff: int) -> int:
    num_set = set(nums)
    count = 0
  
    for num in nums:
        # Check if num+diff and num+2*diff exist in the set
        if num + diff in num_set and num + 2*diff in num_set:
            count += 1
  
    return count

This reduces time complexity to O(n) with O(n) space complexity.

2. Misunderstanding Index vs Value Requirements

A common mistake is confusing the requirement - we need indices (i, j, k) where i < j < k, not just any three values. Some might incorrectly use a set-based approach without considering index ordering.

Solution: If using an optimized approach, ensure the array's strictly increasing property guarantees that if a < b < c in values, their indices also satisfy i < j < k.

3. Integer Overflow in Arithmetic

When calculating num + diff and num + 2*diff, large values might cause integer overflow in languages with fixed integer sizes (though Python handles this automatically).

Solution: Add boundary checks or use appropriate data types:

def arithmeticTriplets(self, nums: List[int], diff: int) -> int:
    num_set = set(nums)
    count = 0
    max_val = nums[-1]  # Last element in sorted array
  
    for num in nums:
        # Check bounds before calculating to avoid unnecessary operations
        if num + 2 * diff > max_val:
            break
        if num + diff in num_set and num + 2 * diff in num_set:
            count += 1
  
    return count

4. Not Leveraging the Sorted Property

The original solution doesn't take advantage of the fact that the array is sorted, which could enable early termination or binary search optimizations.

Solution: Use binary search for O(n log n) solution with better average case performance:

def arithmeticTriplets(self, nums: List[int], diff: int) -> int:
    def binary_search(arr, target):
        left, right = 0, len(arr) - 1
        while left <= right:
            mid = (left + right) // 2
            if arr[mid] == target:
                return True
            elif arr[mid] < target:
                left = mid + 1
            else:
                right = mid - 1
        return False
  
    count = 0
    for i in range(len(nums) - 2):
        # Only search in the remaining part of the array
        if binary_search(nums[i+1:], nums[i] + diff) and \
           binary_search(nums[i+2:], nums[i] + 2 * diff):
            count += 1
  
    return count
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What is the best way of checking if an element exists in a sorted array once in terms of time complexity? Select the best that applies.


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More