Facebook Pixel

2670. Find the Distinct Difference Array

EasyArrayHash Table
Leetcode Link

Problem Description

You are given a 0-indexed array nums of length n.

For each position i in the array, you need to calculate the distinct difference, which is:

  • The number of distinct elements in the prefix nums[0, ..., i] (from start to position i, inclusive)
  • Minus the number of distinct elements in the suffix nums[i + 1, ..., n - 1] (from position i + 1 to the end)

The result should be an array diff where diff[i] contains the distinct difference for position i.

For example, if at position i:

  • The prefix nums[0, ..., i] has 5 distinct elements
  • The suffix nums[i + 1, ..., n - 1] has 3 distinct elements
  • Then diff[i] = 5 - 3 = 2

Special case: When i = n - 1 (last element), the suffix is empty, so it has 0 distinct elements.

The problem asks you to return the distinct difference array for the entire input array nums.

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

Intuition

The straightforward approach would be to calculate the distinct elements in the prefix and suffix for each position i separately. However, this would involve repeatedly counting distinct elements, leading to inefficiency.

The key insight is that we can precompute the distinct element counts for all suffixes first. Why suffixes? Because as we iterate through the array from left to right to build our answer, we're naturally building prefixes incrementally - we can maintain the prefix's distinct elements using a set that grows as we move forward.

Here's the thought process:

  1. Precompute suffix information: If we traverse the array from right to left, we can calculate and store the number of distinct elements for each suffix nums[i, ..., n-1] in an array suf. We use a set to track distinct elements as we move leftward.

  2. Calculate the answer while building prefixes: Now traverse the array from left to right. At each position i:

    • We add nums[i] to our set, which now contains all distinct elements in the prefix nums[0, ..., i]
    • The number of distinct elements in the prefix is simply the size of our set
    • The number of distinct elements in the suffix nums[i+1, ..., n-1] is already stored in suf[i+1]
    • The distinct difference is len(prefix_set) - suf[i+1]

This approach is efficient because we only traverse the array twice and use sets for O(1) average-case lookups and insertions. We avoid recalculating the same information multiple times by preprocessing the suffix counts.

Solution Approach

The solution uses a hash table (set) and preprocessed suffix array to efficiently calculate the distinct differences.

Step 1: Preprocess Suffix Array

First, we create a suffix array suf of size n + 1, where suf[i] stores the number of distinct elements in the suffix starting from index i.

suf = [0] * (n + 1)
s = set()
for i in range(n - 1, -1, -1):
    s.add(nums[i])
    suf[i] = len(s)
  • We traverse the array from right to left (from index n-1 to 0)
  • For each position i, we add nums[i] to the set s
  • The size of the set gives us the number of distinct elements in nums[i, ..., n-1]
  • We store this count in suf[i]
  • Note: suf[n] = 0 by default, representing an empty suffix

Step 2: Calculate Distinct Differences

Next, we clear the set and traverse the array from left to right to build the answer:

s.clear()
ans = [0] * n
for i, x in enumerate(nums):
    s.add(x)
    ans[i] = len(s) - suf[i + 1]
  • We reuse the same set s, but now to track distinct elements in the prefix
  • For each position i:
    • Add nums[i] to the set (building the prefix nums[0, ..., i])
    • len(s) gives the number of distinct elements in the prefix
    • suf[i + 1] gives the number of distinct elements in the suffix nums[i + 1, ..., n - 1]
    • The distinct difference is len(s) - suf[i + 1]

Time Complexity: O(n) - We traverse the array twice, and set operations (add, len) are O(1) on average.

Space Complexity: O(n) - We use an additional array suf of size n + 1 and a set that can contain at most n elements.

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 = [3, 2, 3, 4, 2].

Step 1: Build the suffix array from right to left

We create suf = [0, 0, 0, 0, 0, 0] and an empty set s.

  • i = 4: Add nums[4] = 2 to set → s = {2}suf[4] = 1
  • i = 3: Add nums[3] = 4 to set → s = {2, 4}suf[3] = 2
  • i = 2: Add nums[2] = 3 to set → s = {2, 3, 4}suf[2] = 3
  • i = 1: Add nums[1] = 2 to set → s = {2, 3, 4} (2 already exists) → suf[1] = 3
  • i = 0: Add nums[0] = 3 to set → s = {2, 3, 4} (3 already exists) → suf[0] = 3

Result: suf = [3, 3, 3, 2, 1, 0]

This means:

  • suf[0] = 3: suffix starting at index 0 has 3 distinct elements
  • suf[1] = 3: suffix starting at index 1 has 3 distinct elements
  • suf[2] = 3: suffix starting at index 2 has 3 distinct elements
  • suf[3] = 2: suffix starting at index 3 has 2 distinct elements
  • suf[4] = 1: suffix starting at index 4 has 1 distinct element
  • suf[5] = 0: empty suffix has 0 distinct elements

Step 2: Calculate distinct differences from left to right

Clear the set and create ans = [0, 0, 0, 0, 0].

  • i = 0: Add nums[0] = 3 to set → s = {3} → prefix has 1 distinct, suffix suf[1] = 3ans[0] = 1 - 3 = -2
  • i = 1: Add nums[1] = 2 to set → s = {2, 3} → prefix has 2 distinct, suffix suf[2] = 3ans[1] = 2 - 3 = -1
  • i = 2: Add nums[2] = 3 to set → s = {2, 3} (3 already exists) → prefix has 2 distinct, suffix suf[3] = 2ans[2] = 2 - 2 = 0
  • i = 3: Add nums[3] = 4 to set → s = {2, 3, 4} → prefix has 3 distinct, suffix suf[4] = 1ans[3] = 3 - 1 = 2
  • i = 4: Add nums[4] = 2 to set → s = {2, 3, 4} (2 already exists) → prefix has 3 distinct, suffix suf[5] = 0ans[4] = 3 - 0 = 3

Final answer: [-2, -1, 0, 2, 3]

This matches our expected result where:

  • At index 0: prefix [3] has 1 distinct, suffix [2,3,4,2] has 3 distinct → 1 - 3 = -2
  • At index 1: prefix [3,2] has 2 distinct, suffix [3,4,2] has 3 distinct → 2 - 3 = -1
  • At index 2: prefix [3,2,3] has 2 distinct, suffix [4,2] has 2 distinct → 2 - 2 = 0
  • At index 3: prefix [3,2,3,4] has 3 distinct, suffix [2] has 1 distinct → 3 - 1 = 2
  • At index 4: prefix [3,2,3,4,2] has 3 distinct, suffix [] has 0 distinct → 3 - 0 = 3

Solution Implementation

1class Solution:
2    def distinctDifferenceArray(self, nums: List[int]) -> List[int]:
3        """
4        Calculate the distinct difference array where each element represents
5        the difference between distinct elements in prefix and suffix.
6      
7        For each index i: result[i] = distinct_count(nums[0:i+1]) - distinct_count(nums[i+1:n])
8      
9        Args:
10            nums: Input list of integers
11          
12        Returns:
13            List where each element is the difference between distinct elements 
14            in prefix and suffix at that position
15        """
16        n = len(nums)
17      
18        # suffix_distinct_count[i] stores the count of distinct elements from index i to end
19        suffix_distinct_count = [0] * (n + 1)
20      
21        # Build suffix distinct counts by traversing from right to left
22        distinct_elements = set()
23        for i in range(n - 1, -1, -1):
24            distinct_elements.add(nums[i])
25            suffix_distinct_count[i] = len(distinct_elements)
26      
27        # Clear the set for reuse in prefix calculation
28        distinct_elements.clear()
29      
30        # Initialize result array
31        result = [0] * n
32      
33        # Calculate prefix distinct counts and compute the difference
34        for i, num in enumerate(nums):
35            distinct_elements.add(num)
36            # prefix_distinct_count - suffix_distinct_count (excluding current element)
37            result[i] = len(distinct_elements) - suffix_distinct_count[i + 1]
38      
39        return result
40
1class Solution {
2    public int[] distinctDifferenceArray(int[] nums) {
3        int n = nums.length;
4      
5        // Array to store count of distinct elements from each position to the end
6        // suffixDistinctCount[i] represents the number of distinct elements from index i to end
7        int[] suffixDistinctCount = new int[n + 1];
8      
9        // Set to track unique elements while traversing
10        Set<Integer> uniqueElements = new HashSet<>();
11      
12        // Build suffix distinct count array by traversing from right to left
13        for (int i = n - 1; i >= 0; i--) {
14            uniqueElements.add(nums[i]);
15            suffixDistinctCount[i] = uniqueElements.size();
16        }
17      
18        // Clear the set for reuse in prefix calculation
19        uniqueElements.clear();
20      
21        // Result array to store the difference values
22        int[] result = new int[n];
23      
24        // Calculate prefix distinct count and compute the difference
25        for (int i = 0; i < n; i++) {
26            // Add current element to prefix set
27            uniqueElements.add(nums[i]);
28          
29            // Calculate difference: distinct elements in prefix[0..i] minus distinct elements in suffix[i+1..n-1]
30            result[i] = uniqueElements.size() - suffixDistinctCount[i + 1];
31        }
32      
33        return result;
34    }
35}
36
1class Solution {
2public:
3    vector<int> distinctDifferenceArray(vector<int>& nums) {
4        int n = nums.size();
5      
6        // Array to store count of distinct elements from index i to end
7        // suffixCount[i] = number of distinct elements in nums[i..n-1]
8        vector<int> suffixCount(n + 1, 0);
9      
10        // Set to track unique elements while building suffix counts
11        unordered_set<int> uniqueElements;
12      
13        // Build suffix distinct count array from right to left
14        for (int i = n - 1; i >= 0; --i) {
15            uniqueElements.insert(nums[i]);
16            suffixCount[i] = uniqueElements.size();
17        }
18      
19        // Clear set for reuse in prefix calculation
20        uniqueElements.clear();
21      
22        // Result array to store the difference values
23        vector<int> result(n);
24      
25        // Calculate prefix distinct count and compute difference
26        for (int i = 0; i < n; ++i) {
27            // Add current element to prefix set
28            uniqueElements.insert(nums[i]);
29          
30            // Calculate difference: prefix[0..i] - suffix[i+1..n-1]
31            // prefixCount = uniqueElements.size()
32            // suffixCount[i+1] = distinct elements from i+1 to end
33            result[i] = uniqueElements.size() - suffixCount[i + 1];
34        }
35      
36        return result;
37    }
38};
39
1/**
2 * Calculates the distinct difference array where each element represents
3 * the difference between distinct elements in prefix and suffix
4 * @param nums - Input array of numbers
5 * @returns Array where ans[i] = distinct(nums[0..i]) - distinct(nums[i+1..n-1])
6 */
7function distinctDifferenceArray(nums: number[]): number[] {
8    const arrayLength: number = nums.length;
9  
10    // Array to store count of distinct elements in suffix starting from each index
11    // suffixDistinctCount[i] represents distinct elements from index i to end
12    const suffixDistinctCount: number[] = Array(arrayLength + 1).fill(0);
13  
14    // Set to track unique elements
15    const uniqueElements: Set<number> = new Set<number>();
16  
17    // Build suffix distinct count array by traversing from right to left
18    for (let i: number = arrayLength - 1; i >= 0; i--) {
19        uniqueElements.add(nums[i]);
20        suffixDistinctCount[i] = uniqueElements.size;
21    }
22  
23    // Clear the set for reuse in prefix calculation
24    uniqueElements.clear();
25  
26    // Result array to store the distinct differences
27    const result: number[] = Array(arrayLength).fill(0);
28  
29    // Calculate distinct difference for each position
30    // by building prefix distinct count and subtracting suffix distinct count
31    for (let i: number = 0; i < arrayLength; i++) {
32        uniqueElements.add(nums[i]);
33        // Distinct elements in prefix[0..i] minus distinct elements in suffix[i+1..n-1]
34        result[i] = uniqueElements.size - suffixDistinctCount[i + 1];
35    }
36  
37    return result;
38}
39

Time and Space Complexity

The time complexity is O(n), where n is the length of the array nums. The algorithm consists of two sequential passes through the array:

  • The first loop iterates from index n-1 to 0, performing constant-time operations (set addition and length calculation) at each step, taking O(n) time.
  • The second loop iterates through all elements using enumerate, performing constant-time operations (set addition, length calculation, and subtraction) at each step, also taking O(n) time.
  • Since these loops run sequentially, the total time complexity is O(n) + O(n) = O(n).

The space complexity is O(n), where n is the length of the array nums. The space usage includes:

  • The suf array of size n + 1, which requires O(n) space.
  • The ans array of size n, which requires O(n) space.
  • The set s which can contain at most n distinct elements from nums, requiring O(n) space in the worst case.
  • The total space complexity is O(n) + O(n) + O(n) = O(n).

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

Common Pitfalls

1. Off-by-One Error in Suffix Array Indexing

The Pitfall: A common mistake is incorrectly indexing the suffix array when calculating the distinct difference. Developers often confuse whether suf[i] should represent:

  • The suffix starting from index i (including nums[i]), or
  • The suffix starting from index i + 1 (excluding nums[i])

This confusion leads to using suf[i] instead of suf[i + 1] when calculating the answer, resulting in incorrect results.

Example of Incorrect Code:

# WRONG: Using suf[i] instead of suf[i + 1]
for i, x in enumerate(nums):
    s.add(x)
    ans[i] = len(s) - suf[i]  # ❌ This includes nums[i] in both prefix and suffix

Why This Happens: The problem requires the suffix to start from i + 1 (not including the current element), but when building the suffix array, suf[i] naturally stores the count starting from index i. This creates a mismatch between the stored values and what we need.

The Solution: Always use suf[i + 1] when calculating the distinct difference at position i:

for i, x in enumerate(nums):
    s.add(x)
    ans[i] = len(s) - suf[i + 1]  # ✅ Correct: suffix starts from i + 1

2. Not Clearing the Set Between Prefix and Suffix Calculations

The Pitfall: Forgetting to clear the set after building the suffix array and before calculating the prefix leads to incorrect prefix counts.

Example of Incorrect Code:

# Build suffix array
s = set()
for i in range(n - 1, -1, -1):
    s.add(nums[i])
    suf[i] = len(s)

# WRONG: Forgot to clear the set
# s.clear()  # ❌ Missing this line

ans = [0] * n
for i, x in enumerate(nums):
    s.add(x)  # Set already contains all elements from suffix calculation
    ans[i] = len(s) - suf[i + 1]

The Solution: Always clear the set between the two phases:

s.clear()  # ✅ Essential: Reset the set before prefix calculation

3. Incorrect Suffix Array Size

The Pitfall: Creating the suffix array with size n instead of n + 1, which causes an index out of bounds error when accessing suf[n] (needed when i = n - 1).

Example of Incorrect Code:

suf = [0] * n  # ❌ Should be n + 1
# Later when i = n - 1:
ans[n-1] = len(s) - suf[n]  # IndexError: list index out of range

The Solution: Always allocate n + 1 elements for the suffix array:

suf = [0] * (n + 1)  # ✅ Correct size to handle suf[n] = 0

The extra element suf[n] represents an empty suffix with 0 distinct elements.

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

Which type of traversal does breadth first search do?


Recommended Readings

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

Load More