Facebook Pixel

2475. Number of Unequal Triplets in Array

Problem Description

You are given an array of positive integers nums that is 0-indexed. Your task is to count how many triplets of indices (i, j, k) satisfy specific conditions.

For a valid triplet (i, j, k), the following must be true:

  1. Index ordering: The indices must be in strictly increasing order, meaning 0 <= i < j < k < nums.length. This ensures we're selecting three different positions from the array.

  2. Pairwise distinct values: The values at these three positions must all be different from each other. Specifically:

    • nums[i] != nums[j] (first and second values are different)
    • nums[i] != nums[k] (first and third values are different)
    • nums[j] != nums[k] (second and third values are different)

The solution uses a brute force approach with three nested loops to check every possible combination of three indices. For each combination where i < j < k, it checks if all three values are different from each other. If they are, it increments the count. The time complexity is O(nΒ³) where n is the length of the array, as we examine all possible triplets.

For example, if nums = [4, 4, 2, 4, 3], valid triplets would include (0, 2, 4) because nums[0] = 4, nums[2] = 2, and nums[4] = 3 are all different from each other.

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

Intuition

When we need to find all valid triplets from an array, the most straightforward approach is to examine every possible combination of three elements. Since we need to check specific conditions for each triplet, we can systematically generate all possible triplets and verify if they meet our requirements.

The key insight is that we need three distinct positions i < j < k, and for each such triplet of positions, we need to check if the values at these positions are all different. This naturally leads to a three-level nested loop structure:

  • The outer loop picks the first position i
  • The middle loop picks the second position j (starting from i + 1 to ensure j > i)
  • The inner loop picks the third position k (starting from j + 1 to ensure k > j)

This way, we automatically satisfy the ordering constraint i < j < k through our loop structure. For each generated triplet, we then only need to verify that the three values are pairwise distinct.

The brute force approach works well here because:

  1. We need to examine relationships between three elements, which inherently requires looking at combinations
  2. The constraint checking is simple - just comparing three values for inequality
  3. There's no obvious pattern or mathematical property that would allow us to count valid triplets without examining them

We could optimize this further by using frequency counting or other techniques, but the brute force solution is clear, correct, and easy to implement. It directly translates the problem requirements into code: generate all ordered triplets and count those where all three values are different.

Learn more about Sorting patterns.

Solution Approach

The implementation uses a brute force enumeration approach with three nested loops to check all possible triplets.

Algorithm Steps:

  1. Initialize counter: Start with ans = 0 to keep track of valid triplets.

  2. Triple nested loops:

    • First loop: for i in range(n) - iterates through all possible first positions
    • Second loop: for j in range(i + 1, n) - iterates through all positions after i
    • Third loop: for k in range(j + 1, n) - iterates through all positions after j
  3. Condition checking: For each triplet (i, j, k), check if all three values are pairwise distinct:

    nums[i] != nums[j] and nums[j] != nums[k] and nums[i] != nums[k]
  4. Count valid triplets: The expression in step 3 evaluates to True (which equals 1) when all conditions are met, or False (which equals 0) otherwise. Adding this boolean result to ans effectively counts the valid triplets:

    ans += (nums[i] != nums[j] and nums[j] != nums[k] and nums[i] != nums[k])

Key Implementation Details:

  • The loop structure i < j < k is maintained by starting each inner loop from the previous index + 1
  • Python's boolean-to-integer conversion is utilized: True becomes 1 and False becomes 0 when added to an integer
  • No additional data structures are needed - just the counter variable ans
  • Time complexity: O(nΒ³) as we examine all C(n, 3) possible triplets
  • Space complexity: O(1) as we only use a constant amount of extra space

This straightforward implementation directly translates the problem requirements into code without any optimization tricks, making it easy to understand and verify for correctness.

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 the solution with nums = [1, 3, 1, 5, 4].

We need to find all triplets (i, j, k) where i < j < k and the values at these positions are all different.

Step-by-step execution:

Iteration 1: i = 0 (nums[0] = 1)

  • j = 1, k = 2: Check (0, 1, 2) β†’ nums[0]=1, nums[1]=3, nums[2]=1 β†’ 1β‰ 3 βœ“, 3β‰ 1 βœ“, but 1=1 βœ— β†’ Not valid
  • j = 1, k = 3: Check (0, 1, 3) β†’ nums[0]=1, nums[1]=3, nums[3]=5 β†’ 1β‰ 3 βœ“, 3β‰ 5 βœ“, 1β‰ 5 βœ“ β†’ Valid! Count = 1
  • j = 1, k = 4: Check (0, 1, 4) β†’ nums[0]=1, nums[1]=3, nums[4]=4 β†’ 1β‰ 3 βœ“, 3β‰ 4 βœ“, 1β‰ 4 βœ“ β†’ Valid! Count = 2
  • j = 2, k = 3: Check (0, 2, 3) β†’ nums[0]=1, nums[2]=1, nums[3]=5 β†’ 1=1 βœ— β†’ Not valid
  • j = 2, k = 4: Check (0, 2, 4) β†’ nums[0]=1, nums[2]=1, nums[4]=4 β†’ 1=1 βœ— β†’ Not valid
  • j = 3, k = 4: Check (0, 3, 4) β†’ nums[0]=1, nums[3]=5, nums[4]=4 β†’ 1β‰ 5 βœ“, 5β‰ 4 βœ“, 1β‰ 4 βœ“ β†’ Valid! Count = 3

Iteration 2: i = 1 (nums[1] = 3)

  • j = 2, k = 3: Check (1, 2, 3) β†’ nums[1]=3, nums[2]=1, nums[3]=5 β†’ 3β‰ 1 βœ“, 1β‰ 5 βœ“, 3β‰ 5 βœ“ β†’ Valid! Count = 4
  • j = 2, k = 4: Check (1, 2, 4) β†’ nums[1]=3, nums[2]=1, nums[4]=4 β†’ 3β‰ 1 βœ“, 1β‰ 4 βœ“, 3β‰ 4 βœ“ β†’ Valid! Count = 5
  • j = 3, k = 4: Check (1, 3, 4) β†’ nums[1]=3, nums[3]=5, nums[4]=4 β†’ 3β‰ 5 βœ“, 5β‰ 4 βœ“, 3β‰ 4 βœ“ β†’ Valid! Count = 6

Iteration 3: i = 2 (nums[2] = 1)

  • j = 3, k = 4: Check (2, 3, 4) β†’ nums[2]=1, nums[3]=5, nums[4]=4 β†’ 1β‰ 5 βœ“, 5β‰ 4 βœ“, 1β‰ 4 βœ“ β†’ Valid! Count = 7

Iteration 4: i = 3 (nums[3] = 5)

  • No valid j exists since j must be < 4 and k must be < 5 (array length)

Final Result: 7 valid triplets

The algorithm systematically checks all possible combinations where indices increase (i < j < k) and counts those where all three values differ. The three nested loops ensure we examine every possible triplet exactly once.

Solution Implementation

1class Solution:
2    def unequalTriplets(self, nums: List[int]) -> int:
3        """
4        Count the number of triplets (i, j, k) where i < j < k 
5        and nums[i], nums[j], and nums[k] are all different.
6      
7        Args:
8            nums: List of integers
9          
10        Returns:
11            Number of valid unequal triplets
12        """
13        n = len(nums)
14        count = 0
15      
16        # Iterate through all possible triplets with indices i < j < k
17        for i in range(n):
18            for j in range(i + 1, n):
19                for k in range(j + 1, n):
20                    # Check if all three elements are pairwise different
21                    if nums[i] != nums[j] and nums[j] != nums[k] and nums[i] != nums[k]:
22                        count += 1
23                      
24        return count
25
1class Solution {
2    /**
3     * Counts the number of triplets (i, j, k) where i < j < k and 
4     * nums[i], nums[j], and nums[k] are all different.
5     * 
6     * @param nums The input array of integers
7     * @return The count of unequal triplets
8     */
9    public int unequalTriplets(int[] nums) {
10        int arrayLength = nums.length;
11        int tripletCount = 0;
12      
13        // Iterate through all possible triplet combinations
14        // First element of triplet
15        for (int i = 0; i < arrayLength; i++) {
16            // Second element of triplet (must be after first)
17            for (int j = i + 1; j < arrayLength; j++) {
18                // Third element of triplet (must be after second)
19                for (int k = j + 1; k < arrayLength; k++) {
20                    // Check if all three elements are different
21                    if (nums[i] != nums[j] && 
22                        nums[j] != nums[k] && 
23                        nums[i] != nums[k]) {
24                        tripletCount++;
25                    }
26                }
27            }
28        }
29      
30        return tripletCount;
31    }
32}
33
1class Solution {
2public:
3    int unequalTriplets(vector<int>& nums) {
4        int size = nums.size();
5        int count = 0;
6      
7        // Iterate through all possible triplets (i, j, k) where i < j < k
8        for (int i = 0; i < size; ++i) {
9            for (int j = i + 1; j < size; ++j) {
10                for (int k = j + 1; k < size; ++k) {
11                    // Check if all three elements are pairwise distinct
12                    if (nums[i] != nums[j] && 
13                        nums[j] != nums[k] && 
14                        nums[i] != nums[k]) {
15                        ++count;
16                    }
17                }
18            }
19        }
20      
21        return count;
22    }
23};
24
1/**
2 * Counts the number of triplets (i, j, k) where all three elements are different
3 * @param nums - Array of integers
4 * @returns Number of valid unequal triplets
5 */
6function unequalTriplets(nums: number[]): number {
7    // Get the length of the input array
8    const arrayLength: number = nums.length;
9  
10    // Initialize counter for valid triplets
11    let tripletCount: number = 0;
12  
13    // First loop: iterate through potential first elements of triplets
14    // Stop at arrayLength - 2 to ensure space for j and k
15    for (let i: number = 0; i < arrayLength - 2; i++) {
16      
17        // Second loop: iterate through potential second elements of triplets
18        // Start from i + 1 to avoid duplicates, stop at arrayLength - 1 to ensure space for k
19        for (let j: number = i + 1; j < arrayLength - 1; j++) {
20          
21            // Third loop: iterate through potential third elements of triplets
22            // Start from j + 1 to maintain order and avoid duplicates
23            for (let k: number = j + 1; k < arrayLength; k++) {
24              
25                // Check if all three elements at indices i, j, k are different
26                if (nums[i] !== nums[j] && nums[j] !== nums[k] && nums[i] !== nums[k]) {
27                    // Increment counter when a valid triplet is found
28                    tripletCount++;
29                }
30            }
31        }
32    }
33  
34    // Return the total count of valid unequal triplets
35    return tripletCount;
36}
37

Time and Space Complexity

The time complexity is O(nΒ³), where n is the length of the array nums. This is because the code uses three nested loops: the outer loop runs n times, the middle loop runs up to n-1 times for each iteration of the outer loop, and the inner loop runs up to n-2 times for each iteration of the middle loop. In the worst case, this results in approximately n * (n-1) * (n-2) / 6 iterations, which simplifies to O(nΒ³).

The space complexity is O(1). The algorithm only uses a constant amount of extra space to store the variables n, ans, i, j, and k, regardless of the input size. No additional data structures that scale with the input are created.

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

Common Pitfalls

1. Incorrect Index Range in Nested Loops

A common mistake is setting up the loop ranges incorrectly, which can lead to either missing valid triplets or counting duplicates.

Incorrect Implementation:

# Wrong: Using wrong starting points
for i in range(n):
    for j in range(n):  # Should start from i+1
        for k in range(n):  # Should start from j+1
            if i < j < k and nums[i] != nums[j] != nums[k]:
                count += 1

Problem: This wastes iterations checking invalid index combinations and requires additional logic to ensure i < j < k.

Correct Approach:

for i in range(n):
    for j in range(i + 1, n):  # Start from i+1
        for k in range(j + 1, n):  # Start from j+1
            # No need to check i < j < k since it's guaranteed by loop structure

2. Incorrect Pairwise Comparison Logic

Another frequent error is using chained inequality operators incorrectly for checking distinctness.

Incorrect Implementation:

# Wrong: This doesn't check all pairwise differences
if nums[i] != nums[j] != nums[k]:
    count += 1

Problem: The expression nums[i] != nums[j] != nums[k] in Python means (nums[i] != nums[j]) and (nums[j] != nums[k]). This doesn't check if nums[i] != nums[k]. For example, if nums[i] = 1, nums[j] = 2, nums[k] = 1, the condition would pass even though nums[i] == nums[k].

Correct Approach:

# Explicitly check all three pairs
if nums[i] != nums[j] and nums[j] != nums[k] and nums[i] != nums[k]:
    count += 1

3. Off-by-One Errors in Loop Bounds

Incorrect Implementation:

# Wrong: Missing the last element
for i in range(n-2):
    for j in range(i + 1, n-1):
        for k in range(j + 1, n):

Problem: The first loop should go up to n-2 (inclusive) since we need at least 3 elements, but writing range(n-3) would miss valid triplets.

Correct Approach:

# Can use full range and let inner loops handle bounds
for i in range(n):
    for j in range(i + 1, n):
        for k in range(j + 1, n):
# Or optimize slightly:
for i in range(n - 2):  # Stop when less than 3 elements remain
    for j in range(i + 1, n - 1):  # Stop when less than 2 elements remain
        for k in range(j + 1, n):

4. Performance Consideration for Large Arrays

While not a logical error, using the O(nΒ³) brute force approach on large arrays can cause timeouts.

Alternative Optimization Using Frequency Count:

def unequalTriplets(self, nums: List[int]) -> int:
    from collections import Counter
    freq = Counter(nums)
  
    if len(freq) < 3:
        return 0
  
    result = 0
    prev = 0
    next_count = len(nums)
  
    for count in freq.values():
        next_count -= count
        result += prev * count * next_count
        prev += count
  
    return result

This optimized solution runs in O(n) time by counting frequencies and calculating combinations mathematically.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Consider the classic dynamic programming of longest increasing subsequence:

Find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.

For example, the length of LIS for [50, 3, 10, 7, 40, 80] is 4 and LIS is [3, 7, 40, 80].

What is the recurrence relation?


Recommended Readings

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

Load More