Maximum Candies You Can Get from Boxes
Problem
You have n boxes labeled from 0 to n - 1. You are given four arrays: status, candies, keys, and containedBoxes where:
status[i]is1if theithbox is open and0if theithbox is closed,candies[i]is the number of candies in theithbox,keys[i]is a list of the labels of the boxes you can open after opening theithbox.containedBoxes[i]is a list of the boxes you found inside theithbox.
You are given an integer array initialBoxes that contains the labels of the boxes you initially have. You can take all the candies in any open box and you can use the keys in it to open new boxes and you also can use the boxes you find in it.
Return the maximum number of candies you can get following the rules above.
Examples
Example 1:
Input: status = [1,0,1,0], candies = [7,5,4,100], keys = [[],[],[1],[]], containedBoxes = [[1,2],[3],[],[]], initialBoxes = [0]
Output: 16
Explanation: You will be initially given box 0. You will find 7 candies in it and boxes 1 and 2.
Box 1 is closed and you do not have a key for it so you will open box 2. You will find 4 candies and a key to box 1 in box 2.
In box 1, you will find 5 candies and box 3 but you will not find a key to box 3 so box 3 will remain closed.
Total number of candies collected = 7 + 4 + 5 = 16 candy.
Example 2:
Input: status = [1,0,0,0,0,0], candies = [1,1,1,1,1,1], keys = [[1,2,3,4,5],[],[],[],[],[]], containedBoxes = [[1,2,3,4,5],[],[],[],[],[]], initialBoxes = [0]
Output: 6
Explanation: You have initially box 0. Opening it you can find boxes 1,2,3,4 and 5 and their keys.
The total number of candies will be 6.
Constraints:
n == status.length == candies.length == keys.length == containedBoxes.length1 <= n <= 1000status[i]is either0or1.1 <= candies[i] <= 10000 <= keys[i].length <= n0 <= keys[i][j] < n- All values of
keys[i]are unique. 0 <= containedBoxes[i].length <= n0 <= containedBoxes[i][j] < n- All values of
containedBoxes[i]are unique. - Each box is contained in one box at most.
0 <= initialBoxes.length <= n0 <= initialBoxes[i] < n
Solution
Method 1 – BFS with State Tracking
Intuition
The problem is about collecting candies by opening boxes, where some boxes are locked and can only be opened if you have their keys. The process is similar to traversing a graph where boxes are nodes, and you can only visit (open) a node if you have its key or it's already open. Using BFS ensures we process boxes as soon as they're available, and we keep track of keys and boxes we find along the way.
Approach
- Initialization:
- Use a queue to process boxes you can open.
- Use sets to track boxes you have, keys you have, and boxes already opened.
- Processing:
- For each box in the queue:
- If it's already opened, skip.
- If it's closed and you don't have the key, skip for now.
- If it's open or you have the key:
- Collect candies.
- Mark as opened.
- Add any new keys found to your key set.
- Add any new boxes found to your box set and queue.
- If you now have keys for boxes you couldn't open before, try them again.
- Repeat until no more boxes can be opened.
- Return the total candies collected.
Code
C++
class Solution {
public:
int maxCandies(vector<int>& status, vector<int>& candies, vector<vector<int>>& keys, vector<vector<int>>& containedBoxes, vector<int>& initialBoxes) {
int n = status.size(), ans = 0;
vector<bool> box(n, false), opened(n, false), haveKey(n, false);
queue<int> q;
for (int b : initialBoxes) {
box[b] = true;
q.push(b);
}
while (!q.empty()) {
int sz = q.size();
bool progress = false;
for (int i = 0; i < sz; ++i) {
int b = q.front(); q.pop();
if (opened[b]) continue;
if (!status[b] && !haveKey[b]) {
q.push(b);
continue;
}
ans += candies[b];
opened[b] = true;
for (int k : keys[b]) {
haveKey[k] = true;
if (box[k] && !opened[k]) q.push(k);
}
for (int c : containedBoxes[b]) {
box[c] = true;
if (!opened[c]) q.push(c);
}
progress = true;
}
if (!progress) break;
}
return ans;
}
};
Java
class Solution {
public int maxCandies(int[] status, int[] candies, int[][] keys, int[][] containedBoxes, int[] initialBoxes) {
int n = status.length, ans = 0;
boolean[] box = new boolean[n], opened = new boolean[n], haveKey = new boolean[n];
Queue<Integer> q = new LinkedList<>();
for (int b : initialBoxes) {
box[b] = true;
q.offer(b);
}
while (!q.isEmpty()) {
int sz = q.size();
boolean progress = false;
for (int i = 0; i < sz; ++i) {
int b = q.poll();
if (opened[b]) continue;
if (status[b] == 0 && !haveKey[b]) {
q.offer(b);
continue;
}
ans += candies[b];
opened[b] = true;
for (int k : keys[b]) {
haveKey[k] = true;
if (box[k] && !opened[k]) q.offer(k);
}
for (int c : containedBoxes[b]) {
box[c] = true;
if (!opened[c]) q.offer(c);
}
progress = true;
}
if (!progress) break;
}
return ans;
}
}
Python
class Solution:
def maxCandies(
self,
status: list[int],
candies: list[int],
keys: list[list[int]],
containedBoxes: list[list[int]],
initialBoxes: list[int]
) -> int:
n = len(status)
ans = 0
box = [False] * n
opened = [False] * n
have_key = [False] * n
from collections import deque
q = deque()
for b in initialBoxes:
box[b] = True
q.append(b)
while q:
sz = len(q)
progress = False
for _ in range(sz):
b = q.popleft()
if opened[b]:
continue
if status[b] == 0 and not have_key[b]:
q.append(b)
continue
ans += candies[b]
opened[b] = True
for k in keys[b]:
have_key[k] = True
if box[k] and not opened[k]:
q.append(k)
for c in containedBoxes[b]:
box[c] = True
if not opened[c]:
q.append(c)
progress = True
if not progress:
break
return ans
Complexity
- ⏰ Time complexity:
O(N + total_keys + total_containedBoxes)— Each box, key, and contained box is processed at most once. - 🧺 Space complexity:
O(N)— For tracking box states, keys, and queue.