781. Rabbits in Forest

仅供自己学习

思路:
题目要求最小的颜色种类,这里要从相同数字入手。因为相同数字有两种可能,第一种是多个同种颜色的兔子在说他们这种颜色的有多少只,另一种是不同种颜色有相同的数量,这是解决问题的关键点。
我们需要进行统计找规律。[2,2,2],那么最少种类的可能就是只有一种颜色,数量为3,所有兔子都被问到。[2,2,2,2]这里最少的种类就是两种颜色,数量相同,3个2是同种颜色的,有3只,还有一个2是另外一种颜色,有3只。[2,2,2,2,2]最少种类就是两种,因为一种颜色最多可以有三个兔子,每种颜色三只。那么可以得到如下规律:

回答x的兔子有y只,那么y%(x+1)==0,那么就是y/(x+1)种颜色兔子。如果y%(x+1)!=0,那么就有y/(x+1)+1种颜色兔子,那么我们就需要向上取整。

令cell为向上取整的函数

下面证明 ceil(n/(x+1)) = (n + x) / (x + 1)(为兔子回答的x):

当 n = k * (x + 1)n=k∗(x+1) 的时候,即 nn 是 x + 1x+1 的整数倍时。
左边 ceil(n / (x + 1)) = ceil(k * (x + 1) / (x + 1)) = ceil(k) = kceil(n/(x+1))=ceil(k∗(x+1)/(x+1))=ceil(k)=k。
右边 (n + x) / (x + 1) = (k * (x + 1) + x) / (x + 1) = k + x / (x + 1) = k + 0 = k(n+x)/(x+1)=(k∗(x+1)+x)/(x+1)=k+x/(x+1)=k+0=k
左边等于右边。
当 n = k * (x + 1) + an=k∗(x+1)+a 的时候,即 nn 除以 x + 1x+1 得 k,余数为 a 时 (1 <= a < (x + 1)1<=a<(x+1))。
左边 ceil(n / (x + 1)) = ceil((k * (x + 1) + a) / (x + 1)) = ceil(k + a / (x + 1)) = k + 1ceil(n/(x+1))=ceil((k∗(x+1)+a)/(x+1))=ceil(k+a/(x+1))=k+1。
右边 (n + x) / (x + 1) = (k * (x + 1) + a + x) / (x + 1) = ((k + 1)*(x + 1) + a - 1) / (x + 1) = k + 1 + (a - 1) / (x + 1) = k + 1(n+x)/(x+1)=(k∗(x+1)+a+x)/(x+1)=((k+1)∗(x+1)+a−1)/(x+1)=k+1+(a−1)/(x+1)=k+1。注意这里的 1<= a < (x + 1)1<=a<(x+1),所以 (a - 1) / (x + 1)(a−1)/(x+1) 最小为 (1 - 1) / (x + 1) = 0(1−1)/(x+1)=0;最大为 (x - 1) / (x + 1) = 0(x−1)/(x+1)=0。
左边等于右边。转自

因此我们向上取整的方法为n=x+y,即回答x的兔子数y+x。

代码:

class Solution {
public:
    int numRabbits(vector<int>& answers) {
        unordered_map<int,int> mp;
        int res=0;
        for(auto& an:answers){
            mp[an]++;
        }
        for(auto& [y,x] : mp){
            res += (x+y)/(y+1)*(y+1);
        }
        return res;
    }
};

消耗n个空间,遍历n的长度。那么时间复杂度O(n),空间复杂度O(n)

另一种解法,不用额外空间开销。
先对answer排序,将相同的数连续放在一起,我们记录answer[i]的大小,因为这个大小是用来判断后面连续相同的数是否属于同一个颜色的。answer[i]的值是一种颜色的数量,该数量最大为answer[i]+1,所以如果这个数减到0,还有相同的说明是另一种颜色相同数量的,也要加入进结果里。否则就将i跳到新的数即可。
代码:

class Solution {
public:
    int numRabbits(vector<int>& answers) {
        sort(answers.begin(),answers.end());
        int res=0;
        int n=answers.size();
        for(int i=0;i<n;++i){
            int cnt = answers[i];
            res+=cnt+1;
            while(cnt--&&i+1<n&&answers[i]==answers[i+1])
                i++;
        }
        return res;
    }
};

时间复杂度还是O(n),但是空间复杂度为O(1)

posted @ 2021-04-04 23:25  Mrsdwang  阅读(35)  评论(0编辑  收藏  举报