Maximum Number of Integers to Choose From a Range I
MedPrompt
You are given an integer array banned and two integers n and maxSum. You are choosing some number of integers following the below rules:
- The chosen integers have to be in the range
[1, n]. - Each integer can be chosen at most once.
- The chosen integers should not be in the array
banned. - The sum of the chosen integers should not exceed
maxSum.
Return the maximum number of integers you can choose following the mentioned rules.
Example 1:
Input: banned = [1,6,5], n = 5, maxSum = 6
Output: 2
Explanation: You can choose the integers 2 and 4.
2 and 4 are from the range [1, 5], both did not appear in banned, and their sum is 6, which did not exceed maxSum.Example 2:
Input: banned = [1,2,3,4,5,6,7], n = 8, maxSum = 1
Output: 0
Explanation: You cannot choose any integer while following the mentioned conditions.Example 3:
Input: banned = [11], n = 7, maxSum = 50
Output: 7
Explanation: You can choose the integers 1, 2, 3, 4, 5, 6, and 7.
They are from the range [1, 7], all did not appear in banned, and their sum is 28, which did not exceed maxSum.
Constraints:
1 <= banned.length <= 1041 <= banned[i], n <= 1041 <= maxSum <= 109
Approaches
2 approaches with complexity analysis and trade-offs.
This approach uses a greedy strategy by iterating through numbers from 1 to n and picking the smallest available integers first. To check if a number is banned, it performs a simple linear scan through the banned array. This is the most straightforward but also the least efficient method.
Algorithm
- Initialize
countof chosen integers to 0 andcurrentSum(as a long to prevent overflow) to 0. - Iterate with a number
ifrom 1 ton. - For each
i, perform a linear scan through thebannedarray to check ifiis present. - If
iis not inbannedandcurrentSum + idoes not exceedmaxSum:- Increment
count. - Add
itocurrentSum.
- Increment
- If
currentSum + iexceedsmaxSum, stop the process as any subsequent number will also exceed the limit. - Return the final
count.
Walkthrough
The core idea is to maximize the number of chosen integers. A greedy strategy works best here: by always choosing the smallest possible integers, we leave the maximum possible budget in maxSum for subsequent integers.
The algorithm proceeds as follows:
- Initialize a counter
countto 0 and a running sumcurrentSumto 0. We use alongforcurrentSumto avoid potential overflow sincemaxSumcan be large. - We loop through each integer
ifrom 1 ton. - For each
i, we first check if we can afford to add it. IfcurrentSum + i > maxSum, we break the loop because any number greater thaniwill also violate the condition. - If we can afford
i, we then check if it's a banned number. This is done by iterating through the entirebannedarray. A flag,isBanned, can be used to track this. - If
iis not banned, we choose it: incrementcountand additocurrentSum. - After the loop finishes (either by reaching
nor by exceedingmaxSum), we return the finalcount.
class Solution { public int maxCount(int[] banned, int n, int maxSum) { long currentSum = 0; int count = 0; for (int i = 1; i <= n; i++) { if (currentSum + i > maxSum) { break; } boolean isBanned = false; for (int b : banned) { if (b == i) { isBanned = true; break; } } if (!isBanned) { currentSum += i; count++; } } return count; }}Complexity
Time
O(n * B), where `n` is the upper limit of the range and `B` is the length of the `banned` array. The outer loop runs up to `n` times, and for each iteration, we scan the `banned` array, which takes `O(B)` time.
Space
O(1), as we only use a few variables to store the state, regardless of the input size.
Trade-offs
Pros
Simple to understand and implement.
Very low memory usage as it doesn't require any extra data structures.
Cons
Highly inefficient for the given constraints, with a time complexity of
O(n * B). This is likely to cause a 'Time Limit Exceeded' error on most coding platforms.
This approach also uses the same greedy strategy of picking the smallest available integers first. However, it significantly optimizes the check for banned numbers. By pre-processing the banned array into a HashSet, we can check if a number is banned in average O(1) time, making the overall solution much faster.
Algorithm
- Create a
HashSetto store all the numbers from thebannedarray for efficient lookup. - Initialize
countof chosen integers to 0 andcurrentSum(as a long) to 0. - Iterate with a number
ifrom 1 ton. - For each
i, check if it exists in thebannedset inO(1)average time. - If
iis not in thebannedset andcurrentSum + idoes not exceedmaxSum:- Increment
count. - Add
itocurrentSum.
- Increment
- If
currentSum + iexceedsmaxSum, stop the process. - Return the final
count.
Walkthrough
The bottleneck in the brute-force approach is the repeated linear scan of the banned array. We can eliminate this by using a data structure that provides fast lookups. A HashSet is ideal for this purpose.
The improved algorithm is as follows:
- First, create a
HashSet<Integer>and populate it with all the elements from thebannedarray. This step takesO(B)time, whereBis the length ofbanned. - Initialize
count = 0andcurrentSum = 0L. - Iterate through integers
ifrom 1 ton. - In each iteration, first check if
currentSum + i > maxSum. If it is, we break the loop. - Next, check if
iis in ourbannedSet. This is now anO(1)average time operation. - If
iis not in thebannedSet, we select it by incrementingcountand addingitocurrentSum. - Finally, return the total
count.
This optimization reduces the overall time complexity from quadratic to linear, making it efficient enough for the given constraints.
import java.util.HashSet;import java.util.Set; class Solution { public int maxCount(int[] banned, int n, int maxSum) { Set<Integer> bannedSet = new HashSet<>(); for (int b : banned) { bannedSet.add(b); } long currentSum = 0; int count = 0; for (int i = 1; i <= n; i++) { if (!bannedSet.contains(i)) { if (currentSum + i <= maxSum) { currentSum += i; count++; } else { break; } } } return count; }}Complexity
Time
O(n + B), where `n` is the range limit and `B` is the length of `banned`. It takes `O(B)` to build the set and `O(n)` to iterate from 1 to `n` with constant-time lookups.
Space
O(B), where `B` is the number of elements in the `banned` array. This space is used to store the `HashSet` of banned numbers.
Trade-offs
Pros
Very efficient time complexity, making it suitable for large inputs.
Maintains the simple and intuitive greedy logic.
Cons
Uses extra space proportional to the number of banned items, which could be a concern if memory is extremely constrained.
Solutions
Solution
class Solution {public int maxCount(int[] banned, int n, int maxSum) { Set<Integer> ban = new HashSet<>(banned.length); for (int x : banned) { ban.add(x); } int ans = 0, s = 0; for (int i = 1; i <= n && s + i <= maxSum; ++i) { if (!ban.contains(i)) { ++ans; s += i; } } return ans; }}class Solution {public: int maxCount(vector<int> &banned, int n, int maxSum) { unordered_set<int> ban(banned.begin(), banned.end()); int ans = 0, s = 0; for (int i = 1; i <= n && s + i <= maxSum; ++i) { if (!ban.count(i)) { ++ans; s += i; } } return ans; }};class Solution: def maxCount(self, banned: List[int], n: int, maxSum: int) -> int: ans = s = 0 ban = set(banned) for i in range(1, n + 1): if s + i > maxSum: break if i not in ban: ans += 1 s += i return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.