给你 n 个盒子,每个盒子的格式为 [status, candies, keys, containedBoxes] ,其中:
- 状态字 status[i]:整数,如果 box[i] 是开的,那么是 1 ,否则是 0 。 糖果数 candies[i]: 整数,表示
box[i] 中糖果的数目。 - 钥匙 keys[i]:数组,表示你打开 box[i] 后,可以得到一些盒子的钥匙,每个元素分别为该钥匙对应盒子的下标。
- 内含的盒子 containedBoxes[i]:整数,表示放在 box[i] 里的盒子所对应的下标。
- 给你一个 initialBoxes
数组,表示你现在得到的盒子,你可以获得里面的糖果,也可以用盒子里的钥匙打开新的盒子,还可以继续探索从这个盒子里找到的其他盒子。
请你按照上述规则,返回可以获得糖果的 最大数目 。
初看此题,就打算用bfs解。这道既然属于困难题,那么肯定不能用常规bfs方法套。首先看开盒条件:
- 盒子序号在initialBoxes数组中(手中有这个盒子)
- 盒子序号在keys数组中(手中有盒子的钥匙)
那么可以先尝试写出来bfs的模板:
var maxCandies = function(status, candies, keys, containedBoxes, initialBoxes) {
var ans=0;while(initialBoxes.length){
let temp=initialBoxes.shift();if(status[temp]==1){
ans+=candies[temp];for(let i=0;i<keys[temp].length;i++){
status[keys[temp][i]]=1;}for(let i=0;i<containedBoxes[temp].length;i++){
initialBoxes.push(containedBoxes[temp][i]);}}}return ans;
};
写出来模板问题就清晰多了。我发现这道题的关键在于,遍历时可能当前拥有的盒子刚好此刻没有钥匙。但这并不代表此后不会从其他盒子中开出当前盒子的钥匙,如果只是让当前拥有的盒子简单出队,那么必然会少开很多盒子。
那么很简单,当当前没有钥匙时,我们不要让他出队。
else{
initialBoxes.push(temp);
}
成功解决可能会错过钥匙的问题后,新的问题来了。当题目所给的数据可能无法开完所有盒子时,这段代码将进入死循环。
那么我们需要找到一个跳出循环的办法。我一开始认为,当死循环时,剩余没拿到的钥匙数等于当前拥有盒子数,那么我就用这个条件。然后我就发现这只是死循环的必要不充分条件。
那么怎么样才会算进入死循环呢?其实,只要钥匙集合与拥有盒子的集合没有交集,那么就肯定无法继续开盒子了。那么,最终代码就来了。
var maxCandies = function(status, candies, keys, containedBoxes, initialBoxes) {
var ans=0;while(initialBoxes.length){
let flag=initialBoxes.some(function(item,index,arr){
return status[item]==1;})if(!flag) return ans;let temp=initialBoxes.shift();if(status[temp]==1){
ans+=candies[temp];for(let i=0;i<keys[temp].length;i++){
status[keys[temp][i]]=1;}for(let i=0;i<containedBoxes[temp].length;i++){
initialBoxes.push(containedBoxes[temp][i]);}}else{
initialBoxes.push(temp);}}return ans;
};