Facebook Pixel

3397. Maximum Number of Distinct Elements After Operations


Problem Description

You are given an integer array nums and an integer k.

You are allowed to perform the following operation on each element of the array at most once:

  • Add an integer in the range [-k, k] to the element.

Return the maximum possible number of distinct elements in nums after performing the operations.

Intuition

To solve this problem, we can use a greedy strategy combined with sorting. The goal is to maximize the number of distinct elements in the array after modifying each element within the allowed range.

Key Steps:

  1. Sorting: First, sort the array nums. Sorting helps us to process elements in a structured order so that we can apply the greedy approach effectively.

  2. Initial Setup: Initialize a variable pre to negative infinity to keep track of the latest distinct value we have achieved so far. This helps in ensuring that each new distinct value we choose is indeed distinct.

  3. Iterate and Adjust: For each element x in the sorted array:

    • Calculate the potential new value for the element as min(x + k, max(x - k, pre + 1)).
    • Here, x - k would make the element as small as possible, and pre + 1 ensures this new value is larger than the last distinct value.
    • Take the minimum of x + k and this calculated value to find the feasible distinct value for the current element.
    • If this value is larger than pre, we accept it, increase our distinct count, and update pre.
  4. Result: By iterating through the entire array with this logic, the algorithm ensures that it obtains as many distinct values as possible, given the permissible modifications.

This greedy approach effectively balances increasing each element's distinctness within the constraints of modification by k.

Learn more about Greedy and Sorting patterns.

Solution Approach

To solve the problem of maximizing distinct elements after modifying each element in the array nums within a range [-k, k], we use a greedy approach with the help of sorting. Here is the step-by-step explanation of the solution:

  1. Sorting: First, we sort the array nums. Sorting allows us to approach the problem systematically, dealing with smaller elements first and gradually moving towards larger ones, which helps in making effective use of the available range for modification.

  2. Initialize Variables:

    • We initialize ans to 0 to keep track of the count of distinct elements we manage to achieve.
    • The variable pre is initialized to negative infinity (-inf). This variable keeps track of the last distinct element we have placed. It ensures that the current element is modified to ensure distinctiveness.
  3. Iterate through the Sorted Array:

    • For each element x in the sorted array nums, calculate a potential new value cur.
    • The calculation for cur uses the formula: min(x + k, max(x - k, pre + 1)).
      • x - k: This makes the element as small as possible to maximize the room for distinct values.
      • pre + 1: This ensures the new value is larger than the last distinct value to maintain distinctness.
      • x + k: Represents the maximum possible value within the range we can add to x.
    • We choose the smallest valid value cur that is larger than pre but still within the adjustment range of x + k.
  4. Update Count and Track:

    • If cur (our new distinct candidate for this element) is greater than pre, we know it is a new distinct value.
    • Increment ans by 1.
    • Update pre to cur, marking this as the latest distinct value considered.
  5. Return Result: After processing all elements, ans holds the maximum number of distinct elements that we can achieve after optimal adjustments.

This approach guarantees that each element is modified only once and optimally within the given constraints to achieve the maximum possible distinct values.

Here's the implementation in Python:

class Solution:
    def maxDistinctElements(self, nums: List[int], k: int) -> int:
        nums.sort()
        ans = 0
        pre = -float('inf')
        for x in nums:
            cur = min(x + k, max(x - k, pre + 1))
            if cur > pre:
                ans += 1
                pre = cur
        return ans

This carefully planned greedy strategy efficiently solves the problem with a time complexity dominated by the sorting step, i.e., O(n log n), where n is the length of the array nums.

Ready to land your dream job?

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

Start Evaluator

Example Walkthrough

Let's walk through a small example to illustrate the solution approach.

Example:

  • nums = [1, 2, 2, 3]
  • k = 1

Step 1: Sorting the Array

First, sort the array nums. In this case, the array is already sorted: [1, 2, 2, 3].

Step 2: Initialize Variables

  • Set ans to 0 to count distinct elements.
  • Set pre to -inf as it will track the last distinct value achieved.

Step 3: Iterate through the Sorted Array

  • Element: 1

    • Calculate cur = min(1 + 1, max(1 - 1, -inf + 1))
    • cur = min(2, 1) = 1
    • cur > pre (1 > -inf), so increment ans to 1 and update pre to 1.
  • Element: 2

    • Calculate cur = min(2 + 1, max(2 - 1, 1 + 1))
    • cur = min(3, 2) = 2
    • cur > pre (2 > 1), so increment ans to 2 and update pre to 2.
  • Element: 2

    • Calculate cur = min(2 + 1, max(2 - 1, 2 + 1))
    • cur = min(3, 3) = 3
    • cur > pre (3 > 2), so increment ans to 3 and update pre to 3.
  • Element: 3

    • Calculate cur = min(3 + 1, max(3 - 1, 3 + 1))
    • cur = min(4, 4) = 4
    • cur > pre (4 > 3), so increment ans to 4 and update pre to 4.

Step 4: Return the Result

After processing the entire array, the value of ans is 4, which represents the maximum number of distinct elements we can achieve by modifying the array.

Solution Implementation

1from typing import List
2from math import inf
3
4class Solution:
5    def maxDistinctElements(self, nums: List[int], k: int) -> int:
6        # Sort the input list to handle elements in order.
7        nums.sort()
8      
9        # Initialize the count of distinct elements.
10        distinct_count = 0
11      
12        # Initialize the previous element encountered as negative infinity.
13        previous = -inf
14      
15        for current in nums:
16            # Determine the smallest feasible number within range [current-k, current+k]
17            # that is greater than the previous element.
18            feasible_val = min(current + k, max(current - k, previous + 1))
19          
20            # Check if this feasible value is greater than the previous element.
21            if feasible_val > previous:
22                # Increment the count of distinct elements.
23                distinct_count += 1
24              
25                # Update the previous element to the feasible value.
26                previous = feasible_val
27      
28        # Return the total count of distinct elements achievable.
29        return distinct_count
30
1import java.util.Arrays;
2
3class Solution {
4    public int maxDistinctElements(int[] nums, int k) {
5        // Sort the array to handle elements in a sequential manner
6        Arrays.sort(nums);
7      
8        int n = nums.length; // Length of the array
9        int result = 0; // Variable to store the count of distinct elements
10        int previous = Integer.MIN_VALUE; // Tracks the previous maximum distinct element
11      
12        // Loop through every element in the sorted array
13        for (int x : nums) {
14            // Calculate the current max distinct element 
15            int current = Math.min(x + k, Math.max(x - k, previous + 1));
16          
17            // If the current calculated element is greater than the previous one, it is distinct
18            if (current > previous) {
19                result++; // Increment the count of distinct elements
20                previous = current; // Update the previous element to the current one
21            }
22        }
23      
24        // Return the total count of distinct elements
25        return result;
26    }
27}
28
1#include <vector>
2#include <algorithm>
3#include <climits>
4
5// Define the Solution class
6class Solution {
7public:
8    // Function to find the maximum number of distinct elements in the vector after modifying each element by at most k
9    int maxDistinctElements(std::vector<int>& nums, int k) {
10        // Sort the vector in non-decreasing order
11        std::sort(nums.begin(), nums.end());
12
13        int distinctCount = 0; // To count the number of distinct elements
14        int previous = INT_MIN; // To keep track of the previous element in the sequence
15
16        // Iterate through each number in the sorted vector
17        for (int number : nums) {
18            // Calculate the current number by making it as close to previous + 1 as possible, within the bounds of modifying by ยฑk
19            int current = std::min(number + k, std::max(number - k, previous + 1));
20
21            // Only consider the current number if it's greater than the previous
22            if (current > previous) {
23                ++distinctCount; // Increment distinct count
24                previous = current; // Update the previous element
25            }
26        }
27
28        // Return the count of distinct elements
29        return distinctCount;
30    }
31};
32
1/**
2 * Calculates the maximum number of distinct elements possible by adjusting 
3 * each element within a range of [-k, k].
4 * 
5 * @param nums - An array of numbers.
6 * @param k - An integer representing the range allowed for adjustment.
7 * @returns The maximum count of distinct elements achievable.
8 */
9function maxDistinctElements(nums: number[], k: number): number {
10    // Sort the input array in ascending order.
11    nums.sort((a, b) => a - b);
12
13    // Initialize the count of distinct elements and a variable to track the previous adjusted element.
14    let [ans, pre] = [0, -Infinity];
15
16    // Iterate over each element in the sorted array.
17    for (const x of nums) {
18        // Calculate the current adjusted element, within range [-k, k] and greater than previous.
19        const cur = Math.min(x + k, Math.max(x - k, pre + 1));
20
21        // If the adjusted current number is greater than the previous adjusted number...
22        if (cur > pre) {
23            // Increment the count of distinct elements.
24            ++ans;
25            // Update the previous adjusted element to the current one.
26            pre = cur;
27        }
28    }
29
30    // Return the maximum number of distinct elements.
31    return ans;
32}
33

Time and Space Complexity

The time complexity of the code is O(n \log n). This is because the code includes sorting the list nums, which takes O(n \log n) time, where n is the length of the array nums. The subsequent iteration through the list runs in O(n) time, but the sorting step dominates, resulting in a total time complexity of O(n \log n).

The space complexity is O(\log n), which is used by the sorting algorithm. The built-in Python sort function is typically implemented with Timsort, which has a space complexity of O(\log n) for putting items on the call stack during sorting.

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


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

Which of the following uses divide and conquer strategy?


Recommended Readings

Want a Structured Path to Master System Design Too? Donโ€™t Miss This!


Load More