题目描述
原题链接:森林中的兔子
森林中,每个兔子都有颜色。其中一些兔子(可能是全部)告诉你还有多少其他的兔子和自己有相同的颜色。我们将这些回答放在 answers 数组里。
返回森林中兔子的最少数量。
示例
输入: answers = [1, 1, 2]
输出: 5
解释:
两只回答了 "1" 的兔子可能有相同的颜色,设为红色。
之后回答了 "2" 的兔子不会是红色,否则他们的回答会相互矛盾。
设回答了 "2" 的兔子为蓝色。
此外,森林中还应有另外 2 只蓝色兔子的回答没有包含在数组中。
因此森林中兔子的最少数量是 5: 3 只回答的和 2 只没有回答的。
输入: answers = [10, 10, 10]
输出: 11
解答
分情况讨论:
-
兔兔说没人跟它同一个颜色,直接在 result 上加一就行了
-
兔兔说有 N 只兔兔和它同一个颜色
-
总共有 M 只兔兔的回答是 N,其中(M < N+1),题中问的是最少可能有多少只兔兔,所以我们这里可以假定这 M 只兔兔同一种颜色,即在 result 加上 N+1。因为有 N 只颜色跟自己相同,再加上自己所以是 N+1 只。例如有三只兔兔的回答是 5,那我们就往总数上加上 4。
-
总共有 M 只兔兔的回答是 N,其中(M >= N+1),我们就可以根据这 M 只兔兔的回答确定至少 Math.ceil(M / (N+1)) * (N+1)只兔兔。例如有 7 只兔兔的回答是 5,那么根据贪心准则我们假定前 5 只回答是 5 的兔兔都是同一种颜色,但是不能假定超过 5 只兔兔的回答是 5,那样的话他们回答应该是 6 而不是 5,会自相矛盾。
-
代码实现时,我们遍历所有 answers,当 answer 为 0 时直接给结果加一,不为 0 时用 map 保存回答为同一 answer 的兔兔数,最终同一处理非 0 的回答,代码实现如下:
/**
* @param {number[]} answers
* @return {number}
*/
var numRabbits = function (answers) {
var map = new Map()
var result = 0
answers.forEach(num => {
if (num === 0) {
result++
return
}
if (map.has(num)) {
map.set(num, map.get(num) + 1)
} else {
map.set(num, 1)
}
})
for (let [key, value] of map) {
const times = Math.ceil(value / (key + 1))
result += times * (key + 1)
}
return result
}
复杂度分析
- 时间复杂度:O(N),遍历 N 个回答,再遍历整个 Map 需要 0 至 N 次,所以时间复杂度是 O(N)。
- 空间复杂度:O(N),最坏情况下是所以 answers 里没有重复数,需要用 Map 存储 N 个数,所以空间复杂度是 O(N)。