20210404 LeetCode 每日一题(森林中的兔子)

177 阅读2分钟

题目描述

原题链接:森林中的兔子

森林中,每个兔子都有颜色。其中一些兔子(可能是全部)告诉你还有多少其他的兔子和自己有相同的颜色。我们将这些回答放在  answers  数组里。

返回森林中兔子的最少数量。

示例

输入: answers = [1, 1, 2]
输出: 5
解释:
两只回答了 "1" 的兔子可能有相同的颜色,设为红色。
之后回答了 "2" 的兔子不会是红色,否则他们的回答会相互矛盾。
设回答了 "2" 的兔子为蓝色。
此外,森林中还应有另外 2 只蓝色兔子的回答没有包含在数组中。
因此森林中兔子的最少数量是 5: 3 只回答的和 2 只没有回答的。
输入: answers = [10, 10, 10]
输出: 11

解答

分情况讨论:

  1. 兔兔说没人跟它同一个颜色,直接在 result 上加一就行了

  2. 兔兔说有 N 只兔兔和它同一个颜色

    1. 总共有 M 只兔兔的回答是 N,其中(M < N+1),题中问的是最少可能有多少只兔兔,所以我们这里可以假定这 M 只兔兔同一种颜色,即在 result 加上 N+1。因为有 N 只颜色跟自己相同,再加上自己所以是 N+1 只。例如有三只兔兔的回答是 5,那我们就往总数上加上 4。

    2. 总共有 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)。