You are given an integer array nums
of length n
and a 2D array queries
where queries[i] = [l<sub>i</sub>, r<sub>i</sub>]
. Each queries[i]
represents the following action on nums
:
[l<sub>i</sub>, r<sub>i</sub>]
in nums
by at most 1.A Zero Array is an array with all its elements equal to 0.
Return the maximum number of elements that can be removed from queries
, such that nums
can still be converted to a zero array using the remaining queries. If it is not possible to convert nums
to a zero array, return -1.
Example 1:
nums = [2,0,2], queries = [[0,2],[0,2],[1,1]]
Output: 1
Explanation: After removing queries[2]
, nums
can still be converted to a zero array.
queries[0]
, decrement nums[0]
and nums[2]
by 1 and nums[1]
by 0.queries[1]
, decrement nums[0]
and nums[2]
by 1 and nums[1]
by 0.Example 2:
nums = [1,1,1,1], queries = [[1,3],[0,2],[1,3],[1,2]]
Output: 2
Explanation: We can remove queries[2]
and queries[3]
.
Example 3:
nums = [1,2,3,4], queries = [[0,3]]
Output: -1
Explanation: nums
cannot be converted to a zero array even after using all the queries.
How would you efficiently solve this problem?
A brute-force solution would involve iterating through all possible subsets of the queries
array and, for each subset, checking if it's possible to make the nums
array a zero array. This means checking all 2n subsets of the queries. This would be very computationally expensive.
Code (Python):
from typing import List
def solve():
def can_convert_to_zero(nums: List[int], queries: List[List[int]]) -> bool:
temp_nums = nums[:]
for l, r in queries:
for i in range(l, r + 1):
temp_nums[i] = max(0, temp_nums[i] - 1)
return all(x == 0 for x in temp_nums)
def max_queries_removed(nums: List[int], queries: List[List[int]]) -> int:
n = len(queries)
max_removed = -1
for i in range(1 << n):
subset_queries = []
for j in range(n):
if (i >> j) & 1:
subset_queries.append(queries[j])
remaining_queries = [queries[k] for k in range(n) if not ((i >> k) & 1)]
if can_convert_to_zero(nums, remaining_queries):
max_removed = max(max_removed, bin(i).count('1'))
return max_removed
nums = [2, 0, 2]
queries = [[0, 2], [0, 2], [1, 1]]
result = max_queries_removed(nums, queries)
print(f"Max queries removed: {result}")
nums = [1, 1, 1, 1]
queries = [[1, 3], [0, 2], [1, 3], [1, 2]]
result = max_queries_removed(nums, queries)
print(f"Max queries removed: {result}")
nums = [1, 2, 3, 4]
queries = [[0, 3]]
result = max_queries_removed(nums, queries)
print(f"Max queries removed: {result}")
if __name__ == "__main__":
solve()
Time Complexity: O(2Q * N * Q), where Q is the number of queries and N is the length of nums. We iterate through all 2Q subsets, and for each subset, we iterate through nums
to check if it can be converted to a zero array, using the remaining queries.
Space Complexity: O(N), for creating copies of nums
.
The core idea is to process the numbers in nums
from left to right. For each number, determine the minimum number of queries needed to make that number zero. Then, prioritize the queries that cover indices where the current nums[i]
is positive. The key is to sort queries based on their ending index and greedily apply the queries that end earlier.
nums
: Process the array from left to right.nums[i]
: For each element, decrement it by the amounts provided by the active queries. If nums[i]
is still positive, use additional queries to decrement it to zero.Algorithm Steps:
used
to keep track of how many times each query has been used.queries
array based on the ending index (right endpoint) of each query.nums
array:
nums[i]
, calculate the net decrement applied to it by the used queries.nums[i]
is still positive, iterate through the sorted queries to find those that cover index i
and have remaining uses.nums[i]
and the available decrements of each applicable query.Code (Python):
from typing import List
def solve():
def max_queries_removed(nums: List[int], queries: List[List[int]]) -> int:
n = len(nums)
q = len(queries)
# Sort queries by their end index
queries_with_indices = [(queries[i][0], queries[i][1], i) for i in range(q)]
queries_with_indices.sort(key=lambda x: x[1]) # Sort by the end index
used = [0] * q # How many times each query is used
removed_count = 0
for i in range(n):
decrement = 0
for j in range(q):
if used[j] > 0 and queries_with_indices[j][0] <= i <= queries_with_indices[j][1]:
decrement += used[j]
nums[i] -= decrement
if nums[i] > 0:
applicable_queries = []
for j in range(q):
if queries_with_indices[j][0] <= i <= queries_with_indices[j][1] and used[j] < 1: # Query covers index and not used
applicable_queries.append(j)
if not applicable_queries:
return -1 # Cannot convert to zero array
for j in applicable_queries:
use = min(nums[i], 1 - used[j]) # Use the query as much as possible
used[j] += use
nums[i] -= use
if used[j] == 1:
removed_count += 1
if nums[i] == 0:
break
if nums[i] > 0:
return -1
return q - removed_count
nums = [2, 0, 2]
queries = [[0, 2], [0, 2], [1, 1]]
result = max_queries_removed(nums, queries)
print(f"Max queries removed: {result}")
nums = [1, 1, 1, 1]
queries = [[1, 3], [0, 2], [1, 3], [1, 2]]
result = max_queries_removed(nums, queries)
print(f"Max queries removed: {result}")
nums = [1, 2, 3, 4]
queries = [[0, 3]]
result = max_queries_removed(nums, queries)
print(f"Max queries removed: {result}")
if __name__ == "__main__":
solve()
Time Complexity: O(Q log Q + N * Q), where N is the length of nums
and Q is the number of queries. Sorting takes O(Q log Q), and the nested loop iterates O(N * Q) in the worst case.
Space Complexity: O(Q), for storing the used
array and sorting.
nums
or queries
: Handle cases where either the input array nums
or the queries
array is empty.nums
array to a zero array even using all the queries, return -1.nums
array.