2367. Number of Arithmetic Triplets
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
andi
equalsdiff
:nums[j] - nums[i] == diff
- The difference between the elements at positions
k
andj
also equalsdiff
: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
(wherenums[0] = 0
,nums[2] = 4
,nums[4] = 7
) 4 - 0 = 4
and7 - 4 = 3
(wait, this should benums[1] = 1
,nums[2] = 4
,nums[4] = 7
with differences4 - 1 = 3
and7 - 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.
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:
- The array size is small enough that checking all
C(n, 3)
combinations is feasible - The strictly increasing property ensures no duplicates and maintains order
- 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:
-
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 satisfyi < j < k
wherea = nums[i]
,b = nums[j]
, andc = nums[k]
. -
Check arithmetic progression condition: For each triplet
(a, b, c)
, we verify if:b - a == diff
(first difference equalsdiff
)c - b == diff
(second difference equalsdiff
)
Both conditions must be true for the triplet to be considered arithmetic.
-
Count valid triplets: The solution uses a generator expression inside the
sum()
function. For each triplet, the expressionb - a == diff and c - b == diff
evaluates toTrue
(which equals 1) if both conditions are met, orFalse
(which equals 0) otherwise. Thesum()
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 EvaluatorExample 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:
- (3, 7, 11) forms the arithmetic sequence 3 β 7 β 11 with common difference 4
- (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
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
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!