945. Minimum Increment to Make Array Unique
Problem Description
You're handed an array of integers named nums
. The task is to make each number in the array unique by performing a certain operation: for any element at index i
, where 0 <= i < nums.length
, you can increase the value of nums[i]
by 1
. The goal is to find out the minimum number of such increments needed to ensure that all elements in the array are unique. It is guaranteed that the final answer will be small enough to fit within a 32-bit integer.
Intuition
The intuitive solution involves:
- First, sort the array. This ensures that we can process numbers in a sequence and efficiently deal with duplicates.
- Then, iterate through the array starting from the second element, comparing each element with the one before it.
- If the current element is less than or equal to the previous element, it means we have a duplicate or a possibility of a non-unique value.
- To make the current value unique, we need to increment it to be just one more than the previous value. The difference plus one
d = nums[i - 1] - nums[i] + 1
gives the exact number of increments needed for that element. - We update the current element to its new unique value and add the number of increments
d
to a running total, which will eventually be the answer. - Repeat this process for all elements in the array. By the end, the running total gives us the minimum number of moves necessary to achieve uniqueness for all elements in
nums
.
Solution Approach
The solution utilizes a simple but effective algorithm which requires minimal data structures – the primary one being the ability to sort the given array. Here's the approach outlined step by step:
-
Sorting the Array: Start by sorting the
nums
array. This allows us to process the array in ascending order and handle any duplicates or clusters of the same number effectively. -
Initialization: A variable,
ans
, is initialized to0
. This variable will keep track of the total number of increments we perform across the entire array. -
Iterate Through the Array: Iterate through the sorted
nums
starting from the index1
to the end of the array. We compare each element with the previous one to check for duplicates or the sequence being out of order. -
Processing Each Element:
- For each element at index
i
, check if it's less than or equal to the element at indexi - 1
. - If it is, we need to increment it to make it unique. We calculate the
difference + 1
bynums[i - 1] - nums[i] + 1
, which tells us how much we need to increment the current element to not only make it unique but also ensure it's greater than the previous element. - Add this difference to the
nums[i]
to update the value of the current element, making it unique. - Also, add this difference to the
ans
variable, which accumulates the total increments made.
- For each element at index
-
Returning the Answer: After the loop terminates,
ans
holds the total number of increments needed to make all elements in the array unique. Returnans
.
This solution is quite efficient with a time complexity of O(n log n)
due to the sort operation. The following loop has a complexity of O(n)
, but since sorting takes precedence in terms of complexity analysis, it doesn't change the overall time complexity.
The Python code implementation following this algorithm ensures that with minimal space overhead, and in a reasonably optimal time, we arrive at the least number of moves needed to make every element in the array nums
unique.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Given an array of integers nums = [3, 2, 1, 2]
, our task is to make each number in the array unique with the least number of increments.
Following the solution approach, let's walk through the process:
-
Sorting the Array:
- We start by sorting
nums
. After sorting, the array becomesnums = [1, 2, 2, 3]
.
- We start by sorting
-
Initialization:
- Next, we initialize the answer variable
ans
to0
. This variable will count the total increments.
- Next, we initialize the answer variable
-
Iterate Through the Array:
- We then iterate through the sorted
nums
beginning from the index1
.
- We then iterate through the sorted
-
Processing Each Element:
- At index
1
,nums[0] = 1
andnums[1] = 2
. Sincenums[1]
is greater thannums[0]
, no increment is needed. - At index
2
, we have a duplicate sincenums[2] = 2
andnums[1]
was also2
. We need to incrementnums[2]
by1
to make it unique. Sonums[2]
becomes3
andans
is incremented by1
(total increments so far:1
). - However, now at index
3
,nums[3] = 3
which is equal tonums[2]
after the previous increment. So, we need to incrementnums[3]
until it is unique. The next unique value would be4
, which means we need to incrementnums[3]
by1
. Nownums[3]
becomes4
, and we add1
toans
making the total increments2
.
- At index
-
Returning the Answer:
- After processing each element, the modified array is
nums = [1, 2, 3, 4]
, andans = 2
. Therefore, the minimum number of increments needed to ensure all elements are unique is2
.
- After processing each element, the modified array is
The array modification steps are summarized as follows:
- Initial Array:
[3, 2, 1, 2]
- After Sorting:
[1, 2, 2, 3]
- Make
nums[2]
unique:[1, 2, 3, 3]
(ans = 1
) - Make
nums[3]
unique:[1, 2, 3, 4]
(ans = 2
)
Return ans
, which is 2
. If we apply the same approach to any array using the described algorithm, we will determine the minimum increments necessary to make all elements unique.
Solution Implementation
1class Solution:
2 def minIncrementForUnique(self, nums: List[int]) -> int:
3 # Sort the input list to ensure duplicate or smaller values follow larger values.
4 nums.sort()
5
6 # Initialize the answer to count the minimum increment required.
7 increments_needed = 0
8
9 # Iterate through the list starting from the second element.
10 for i in range(1, len(nums)):
11 # If the current number is less than or equal to the previous number,
12 # it's not unique or needs to be incremented to be unique.
13 if nums[i] <= nums[i - 1]:
14 # Calculate the difference needed to make the current number
15 # greater than the previous number by one.
16 diff = nums[i - 1] - nums[i] + 1
17
18 # Increment the current number by the calculated difference.
19 nums[i] += diff
20
21 # Add the difference to the increments needed.
22 increments_needed += diff
23
24 # Return the total number of increments needed to make all numbers unique.
25 return increments_needed
26
1class Solution {
2 public int minIncrementForUnique(int[] nums) {
3 // Sort the input array to make it easier to deal with duplicates
4 Arrays.sort(nums);
5
6 // Initialize a variable to keep track of the number of increments needed
7 int increments = 0;
8
9 // Start iterating from the second element (i = 1) since we compare with the previous one
10 for (int i = 1; i < nums.length; ++i) {
11 // If the current element is less than or equal to the previous one, it's not unique
12 if (nums[i] <= nums[i - 1]) {
13 // Calculate the difference needed to make the current element unique
14 int difference = nums[i - 1] - nums[i] + 1;
15
16 // Increment the current element by the needed difference
17 nums[i] += difference;
18
19 // Accumulate the total increments needed
20 increments += difference;
21 }
22 }
23
24 // Return the total number of increments needed for the array to have all unique elements
25 return increments;
26 }
27}
28
1#include <vector>
2#include <algorithm> // Include necessary headers
3
4class Solution {
5public:
6 int minIncrementForUnique(vector<int>& nums) {
7 // Sort the input array to arrange numbers in non-decreasing order.
8 sort(nums.begin(), nums.end());
9
10 // Initialize the variable to store the minimum increments needed.
11 int minIncrements = 0;
12
13 // Iterate through the array starting from the second element.
14 for (int i = 1; i < nums.size(); ++i) {
15 // Check if the current element is less than or equal to the previous element.
16 if (nums[i] <= nums[i - 1]) {
17 // Calculate the difference needed to make the current number unique.
18 int difference = nums[i - 1] - nums[i] + 1;
19
20 // Increment the current number by the calculated difference.
21 nums[i] += difference;
22
23 // Add the difference to the total number of increments needed.
24 minIncrements += difference;
25 }
26 }
27
28 // Return the total minimum increments needed to make all the nums unique.
29 return minIncrements;
30 }
31};
32
1// Import array and algorithm functionality
2function sortArray(nums: number[]): number[] {
3 return nums.sort((a, b) => a - b);
4}
5
6function minIncrementForUnique(nums: number[]): number {
7 // Sort the input array to arrange numbers in non-decreasing order.
8 nums = sortArray(nums);
9
10 // Initialize the variable to store the minimum increments needed.
11 let minIncrements: number = 0;
12
13 // Iterate through the array starting from the second element.
14 for (let i = 1; i < nums.length; i++) {
15 // Check if the current element is less than or equal to the previous element.
16 if (nums[i] <= nums[i - 1]) {
17 // Calculate the difference needed to make the current number unique.
18 const difference: number = nums[i - 1] - nums[i] + 1;
19
20 // Increment the current number by the calculated difference.
21 nums[i] += difference;
22
23 // Add the difference to the total number of increments needed.
24 minIncrements += difference;
25 }
26 }
27
28 // Return the total minimum increments needed to make all the numbers unique.
29 return minIncrements;
30}
31
Time and Space Complexity
Time Complexity
The time complexity of the provided code is determined by several factors:
-
Sorting the input list, which is
nums.sort()
. This operation is typically implemented using an algorithm like Timsort (in Python's sort function), which has a time complexity ofO(n log n)
wheren
is the number of elements in the list. -
A single
for
loop that iterates over the sorted listnums
, which adds a time complexity ofO(n)
.
Hence, the total time complexity is dominated by the sorting operation, which gives us:
Time Complexity: O(n log n)
Space Complexity
The space complexity of the provided code is :
- No extra space is used apart from the initial input list and a variable
ans
that keeps track of the increments needed to make each element in the list unique. This results in a constant amount of additional space being used, i.e.,O(1)
.
Space Complexity: O(1)
Learn more about how to find time and space complexity quickly using problem constraints.
What's the output of running the following function using input 56
?
1KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13 def dfs(path, res):
14 if len(path) == len(digits):
15 res.append(''.join(path))
16 return
17
18 next_number = digits[len(path)]
19 for letter in KEYBOARD[next_number]:
20 path.append(letter)
21 dfs(path, res)
22 path.pop()
23
24 res = []
25 dfs([], res)
26 return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2 '2', "abc".toCharArray(),
3 '3', "def".toCharArray(),
4 '4', "ghi".toCharArray(),
5 '5', "jkl".toCharArray(),
6 '6', "mno".toCharArray(),
7 '7', "pqrs".toCharArray(),
8 '8', "tuv".toCharArray(),
9 '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13 List<String> res = new ArrayList<>();
14 dfs(new StringBuilder(), res, digits.toCharArray());
15 return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19 if (path.length() == digits.length) {
20 res.add(path.toString());
21 return;
22 }
23 char next_digit = digits[path.length()];
24 for (char letter : KEYBOARD.get(next_digit)) {
25 path.append(letter);
26 dfs(path, res, digits);
27 path.deleteCharAt(path.length() - 1);
28 }
29}
30
1const KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13 let res = [];
14 dfs(digits, [], res);
15 return res;
16}
17
18function dfs(digits, path, res) {
19 if (path.length === digits.length) {
20 res.push(path.join(''));
21 return;
22 }
23 let next_number = digits.charAt(path.length);
24 for (let letter of KEYBOARD[next_number]) {
25 path.push(letter);
26 dfs(digits, path, res);
27 path.pop();
28 }
29}
30
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
LeetCode 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 we
Want a Structured Path to Master System Design Too? Don’t Miss This!