leetcode 第 226 场算法比赛

作者: | 更新日期:

思路不顺,第一题写了十几分钟,排名依旧是一百名外摇摆。

本文首发于公众号:天空的代码世界,微信号:tiankonguse

零、背景

这次比赛脑子总是卡壳,思路想着想着就不知道想到哪了,然后重新读题、重新思考。

这难道就是年龄大了的缘故吗?

看来不少人卡壳。

源代码:

https://github.com/tiankonguse/leetcode-solutions/tree/master/contest/2/226

一、盒子中小球的最大数量

题意:给编号 [lowLimit ,highLimit]的小球,以及 [1,infinity]的盒子。
一个小球可以放在小球编号上每位数字之和对应的盒子里。
问小球数量最多的盒子里面,小球最多有多少个。

思路:求放盒子的逻辑我不知怎么,一直没看懂,读了十分钟题目。

看懂后,直接暴力计算每个小球应该放在哪个盒子里,然后遍历所有盒子求球的最大值即可。

int countBalls(int lowLimit, int highLimit) {
    unordered_map<int, int> m;
    
    int ans = 0;
    for(int i=lowLimit;i<=highLimit;i++){
        int sum = 0;
        int tmp = i;
        while(tmp){
            sum += tmp%10;
            tmp /= 10;
        }
        
        m[sum]++;
        ans = max(ans, m[sum]);
    }
    
    return ans;
}

二、从相邻元素对还原数组

题意:给 n 个互不相同的数字,现在不知道数字的顺序,但是知道相邻数字的关系。
现在告诉你 n-1对数字关系,求数字的顺序(正序或反序都可以)。

思路:可以当做图论题来做,找到入度为1 的起点,搜索即可。

注意事项:中间的点度数都是 2,搜索的时候,对搜过的点左下标记即可。
我是直接标记来源的父节点的,因为图是链,父节点是唯一的。

int n = m.size();

vector<int> ans;
ans.reserve(n);

int preStart = start;
for(int i=0;i<n;i++){
    ans.push_back(start);
    
    auto& p = m[start];
    
    int newStart = start;
    for(auto v: p){
        if(v != preStart){
            newStart = v;
        }
    }
    preStart = start; // 更新父节点
    start = newStart; // 更新当前节点
}
return ans;

三、吃糖果

题意:有 n 类糖果,每类有若干个。
糖果每天至少需要吃一个,而且必须按类数的编号从小到大吃(可以同时吃多类糖果)。
问在每天至多吃 cap 糖果的情况下,第 x 天是否可以吃到第 y 类糖果。

思路:一看是看到题我是懵逼的。
思考了一下发现就是个前缀和的问题。

问题我们可以转化一下,问在每天至多吃 cap 的糖果下,都能在哪些天吃到第 y 类糖果。

明显可以看出,答案是一个连续区间。
最大的天数肯定是每天吃一个,最大天数就是 sum[0~y]-1 了。
最小的天数则是每天吃 cap 个糖果,最小天数就是 sum[0~y-1]/cap了。

处理好加一减一问题,得到天数区间,判断询问的天数是否在这个区间内即可。

for(auto& p: queries){
    int type = p[0];
    ll day = p[1];
    ll cap = p[2];
    
    ll minDay = 0, maxDay = 0; // [minDay ,maxDay]
    if(type > 0){
        minDay = sum[type - 1]/cap;
    }
    maxDay = sum[type] - 1; 
    ans.push_back(day >= minDay && day <= maxDay);
}

四、回文串分割 IV

题意:给一个字符串,问能否将字符串分隔为三个连续子串,每个子串都是回文串。

思路:刚看到题,感觉会很难。
但是一看数据范围,只有 2000,那果断暴力枚举了。

使用O(n^2)的复杂度预处理出所有连续子串是否是回文子串。
然后再使用 O(n^2)的复杂度枚举所有分隔情况是否是答案。

n = s.length();
memset(dp, 0, sizeof(dp));

for(int i=0;i<n;i++){
    TryCenter(i, i);  // i 为中心
    TryCenter(i-1, i); // i-1~i 为中心
}

for(int l=1;l<n;l++){
    for(int r=l;r<n-1;r++){
        // [0, l-1], [l, r], [r+1, n-1]
        if(dp[0][l-1] && dp[l][r] && dp[r+1][n-1]){
            return true;
        }
    }
}
return false;

五、最后

这次比赛题目没涉及复杂的算法,都是基本数据结构。
剩下的就是注意边界问题以及练手速了。

加油,算法人。

《完》

-EOF-

本文公众号:天空的代码世界
个人微信号:tiankonguse
公众号ID:tiankonguse-code

本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。

关注公众号,接收最新消息

tiankonguse +
穿越