LeetCode 2216 - Minimum Deletions to Make Array Beautiful
The problem asks us to transform a given integer array nums into a beautiful array using the minimum number of deletions. A beautiful array satisfies two conditions: its length is even, and no two consecutive elements at even indices are equal (nums[i] !
Difficulty: 🟡 Medium
Topics: Array, Stack, Greedy
Solution
Problem Understanding
The problem asks us to transform a given integer array nums into a beautiful array using the minimum number of deletions. A beautiful array satisfies two conditions: its length is even, and no two consecutive elements at even indices are equal (nums[i] != nums[i + 1] for all i % 2 == 0). Deletions are performed such that elements to the right shift left, and elements to the left remain unchanged.
The input is a list of integers, with up to 10^5 elements, each ranging from 0 to 10^5. The expected output is a single integer representing the minimum number of deletions required to achieve a beautiful array. An empty array is trivially considered beautiful.
Key edge cases include arrays that are already beautiful, arrays with repeated consecutive elements, and arrays of length 1 (which require deletion to become even-length). The problem guarantees that the array is non-empty, but we must handle small arrays carefully.
Approaches
A brute-force approach would attempt to generate all subsequences of the array and check if each is beautiful. This is correct but computationally infeasible, as the number of subsequences grows exponentially with array length, resulting in O(2^n) time complexity.
The key insight for an optimal approach is that we only need to check adjacent pairs of elements at even indices. By maintaining a "virtual" length while iterating through the array and only appending elements that do not violate the beautiful condition, we can greedily count how many elements need to be removed. After processing, we also need to ensure the final array has an even length, potentially deleting the last element if necessary.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(2^n) | O(n) | Generates all subsequences and checks each for beauty |
| Optimal | O(n) | O(1) | Greedy traversal, counting deletions based on adjacent duplicates and final length parity |
Algorithm Walkthrough
- Initialize a variable
deletionsto0to count the number of elements removed. - Initialize a variable
lengthto0representing the length of the "virtual" beautiful array being built. - Iterate through each element
numinnums. - For each element, check if it violates the beautiful property: if the current
lengthis even andnumequals the last appended element in the virtual array, incrementdeletionsand skip appending. - Otherwise, increment
lengthto includenumin the virtual array. - After iterating through all elements, check if
lengthis odd. If so, incrementdeletionsto remove the last element to ensure even length. - Return
deletionsas the minimum number of deletions required.
Why it works: By processing the array in a single pass and ensuring that no even-indexed pair violates the beautiful condition, we greedily maintain a valid array. The final adjustment for even length ensures completeness, guaranteeing the minimum deletions.
Python Solution
from typing import List
class Solution:
def minDeletion(self, nums: List[int]) -> int:
deletions = 0
length = 0 # length of the virtual beautiful array
for num in nums:
if length % 2 == 0 and length > 0 and nums[length - deletions - 1] == num:
deletions += 1
else:
length += 1
if length % 2 == 1:
deletions += 1
return deletions
The implementation uses a single pass through nums, maintaining the virtual array length with length and incrementing deletions whenever an element would violate the beautiful property. The final parity check ensures the resulting array has even length.
Go Solution
func minDeletion(nums []int) int {
deletions := 0
length := 0
for _, num := range nums {
if length%2 == 0 && length > 0 && nums[length-deletions-1] == num {
deletions++
} else {
length++
}
}
if length%2 == 1 {
deletions++
}
return deletions
}
The Go solution mirrors the Python version. Slices in Go allow direct indexing. The length-deletions-1 calculation ensures we compare the current element with the last element in the virtual array, similar to Python.
Worked Examples
Example 1: nums = [1,1,2,3,5]
| Step | num | length | deletions | Notes |
|---|---|---|---|---|
| 1 | 1 | 1 | 0 | Append first element |
| 2 | 1 | 1 | 1 | Duplicate at even index, delete |
| 3 | 2 | 2 | 1 | Append |
| 4 | 3 | 3 | 1 | Append |
| 5 | 5 | 4 | 1 | Append |
Final length is even, so no extra deletion. Result: 1.
Example 2: nums = [1,1,2,2,3,3]
| Step | num | length | deletions | Notes |
|---|---|---|---|---|
| 1 | 1 | 1 | 0 | Append |
| 2 | 1 | 1 | 1 | Delete duplicate |
| 3 | 2 | 2 | 1 | Append |
| 4 | 2 | 2 | 2 | Delete duplicate |
| 5 | 3 | 3 | 2 | Append |
| 6 | 3 | 3 | 3 | Delete duplicate |
Final length is odd, add one more deletion to make even. Result: 2.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Single pass through the array |
| Space | O(1) | Only counters deletions and length are used |
Since we only traverse the array once and use constant extra space, this is optimal for the input constraints.
Test Cases
# Provided examples
assert Solution().minDeletion([1,1,2,3,5]) == 1 # minimal deletion to make beautiful
assert Solution().minDeletion([1,1,2,2,3,3]) == 2 # two deletions required
# Edge cases
assert Solution().minDeletion([1]) == 1 # length 1, must delete to be even
assert Solution().minDeletion([1,2]) == 0 # already beautiful
assert Solution().minDeletion([1,1,1,1]) == 2 # repeated duplicates
assert Solution().minDeletion([]) == 0 # empty array is beautiful
# Large array
assert Solution().minDeletion([i % 2 for i in range(100000)]) == 0 # alternating pattern
| Test | Why |
|---|---|
[1,1,2,3,5] |
minimal deletion to fix duplicate at even index |
[1,1,2,2,3,3] |
multiple deletions needed across array |
[1] |
single-element edge case |
[1,2] |
already beautiful |
[1,1,1,1] |
repeated duplicates |
[] |
empty array case |
| large alternating array | tests algorithm efficiency on upper-bound |
Edge Cases
One important edge case is a single-element array. Since the beautiful array must have even length, any single-element array requires deletion. The implementation handles this with the final parity check.
Another edge case is an array with alternating duplicates, such as [1,1,2,2,3,3,...]. These require deletions at multiple points; the greedy approach ensures we only delete when necessary without over-deleting.
A third edge case is an already beautiful array of even length. The algorithm correctly skips all elements and does not increment deletions, preserving the minimal deletion property.