「第 327 场周赛」参赛总结:不要在赛场上绣花和内耗
2674
2023.01.08
发布于 未知归属地
  1. 成绩
  2. 第一题
  3. 第二题
  4. 第三题
  5. 题目四
  6. 总结

成绩

来咱扣三个月了,一开始知道可以打比赛时很兴奋,参加了第 315 场周赛第 89 场双周赛,深受打击🤣,特别是「第 89 场双周赛」,第一道简单题就耗了半个小时,第二题更是看题看的头晕,直接就弃赛了。我也是现在才知道,弃赛真的对自己不负责任哈哈。

昨天简单研究了一下赛制,虽然对打分的算法原理还没彻底搞懂,但是大体上知道怎么回事了,刚才鼓起勇气参加了第 327 场周赛。严格地说,这是我第一场严肃对待的比赛。

我做对了前三道,耗时 48:23;在 3631 个有效参赛选手中,排名 930;在得分相同的 1556 名前三题选手中,我排名 745

前三题选手中,最快的选手 05:07 之内就完成了,我真的望洋兴叹。

这场比赛中,四题选手,以及放弃第三题解出第四题的选手,总共 184 人,望洋兴叹 again。

截屏2023-01-08 12.48.35.png
截屏2023-01-08 12.52.55.png

意外发现,每位参赛的代码都是公开的,还可以举报。很赞,这样可以让比赛更透明。

第一题

正整数和负整数的最大计数

耗时 03:33。

这道题十分简单,但是题干中提示非递减数组,所以用二分查找会更高效,我纠结了一下,这一纠结,就浪费了时间。最后考虑到这是比赛,要争分夺秒,无脑遍历显然更好写:

class Solution {
    public int maximumCount(int[] nums) {
        int pos = 0, neg = 0;
        for(int x: nums){
            if(x > 0)pos++;
            if(x < 0)neg++;
        }
        return Math.max(pos, neg);
    }
}

第二题

执行 K 次操作后的最大分数

耗时 9 分钟。

因为第一题浪费了时间,略为懊恼,所以这道题,在读题的时候我感觉有点紧张,一目十行,眼花缭乱,又怕理解错题,反复读了两边。

很快就想到了用优先队列,复杂度 。但是我紧张兮兮的,反复确定数组里是不是都是正数反复检查 n 的数量级会不会导致超时反复担心求和会不会导致正数越界

最尴尬的是,我怎么也不会拼写 PriorityQueue这个词,最后无奈打开 IDEA,根据拼写提示才搞定。

时间就是这么浪费的,我不知道我紧张兮兮的干什么🤣

class Solution {
    public long maxKelements(int[] nums, int k) {
        PriorityQueue<Integer> pq = new PriorityQueue<>((n1, n2)->n2 - n1);
        for(int x: nums)pq.offer(x);
        long ret = 0;
        while(k-- > 0){
            int q = pq.poll();
            ret += q;
            pq.offer((int)Math.ceil((double)q/3));
        }
        return ret;
    }
}

第三题

使字符串总不同字符的数目相等

这道题耗时 36:10,还有一次错误提交,导致罚时间 5 分钟,也是耗时最长、我最懊恼的题目🤣

本来,前两道题很顺利,所以第三题我轻松了不少。思路也很快想出来了,先遍历两个字符串,对字符计数,然后双循环暴力考察,时间复杂度 是两个字符串长度, 是字符集大小,这道题是 26。

但是,编码的过程中,我陷入了泥潭。先是在那个双重循环里,四个 if 判断写的我眼花缭乱,细细检查后,依然怎么也通不过。

然后各种用 System.out.printf 调试。我发现,写那个双循环时,我写成了:

for(int i = 0; i < 26; i++){
    if(cnt1[0] == 0)continue;
    for(int j = 0; i < 26; i++){}
}

这就是复制粘贴导致的后果,我自己复制粘贴我自己(# ̄~ ̄#),眼睛一花就会看错。最离谱的是,我发现问题后,改成了

for(int i = 0; i < 26; i++){
    if(cnt1[0] == 0)continue;
    for(int j = 0; i < 26; j++){}
}

依然是死都调试不同。这样低端的错误,真的想抽自己🤣🤣🤣🤣🤣

然后,调通了官方样例,信心满满地递交了,喜提罚时五分钟🙃:

class Solution {
    public boolean isItPossible(String word1, String word2) {
        int[] cnt1 = new int[26];
        int[] cnt2 = new int[26];
        int c1 = 0, c2 = 0;
        for(char c: word1.toCharArray()){
            if(cnt1[c - 'a']++ == 0)c1++;
        }
        for(char c: word2.toCharArray()){
            if(cnt2[c - 'a']++ == 0)c2++;
        }
        // System.out.printf("%s, %s\n", c1, c2);
        for(int i = 0; i < 26; i++){
            if(cnt1[i] == 0)continue;
            for(int j = 0; j < 26; j++){
                if(cnt2[j] == 0)continue;
                int t1 = c1, t2 = c2;
                if(cnt1[j] == 0)t1++;
                if(cnt1[i] == 1 )t1--;
                if(cnt2[i] == 0)t2++;
                if(cnt2[j] == 1)t2--;
                // System.out.printf("%s, %s, %s, %s, %s, %s\n", c1, c2, (char)('a' + i), (char)('a' + j), t1, t2);
                if(t1 == t2)return true;
            }
        }
        return false;
    }
}

检查哪里错了,真的很难检查出来,幸运的是,居然给出了卡住的用例:

"aa"
"ab"

如果我理智一点,保持清醒,不要懊恼,那看到这个用例很快就能知道症结了(交换相同的字符时我没处理),但是我慌乱了,我担心第四题没时间了。

所以继续痛苦地、无脑地、漫山遍野地 System.out.printf,这是本场比赛最失败、最不应该的地方,耗时颇多。而且,如果不是幸运滴看到了卡住的用例,可能真的要调试到猴年马月🙃。

正确版本如下(你可以看到,虽然 AC 了,但是我这段代码真的已经放飞自我了🤣):

image.png

class Solution {
    public boolean isItPossible(String word1, String word2) {
        int[] cnt1 = new int[26];
        int[] cnt2 = new int[26];
        int c1 = 0, c2 = 0;
        for(char c: word1.toCharArray()){
            if(cnt1[c - 'a']++ == 0)c1++;
        }
        for(char c: word2.toCharArray()){
            if(cnt2[c - 'a']++ == 0)c2++;
        }
        // System.out.printf("%s, %s\n", c1, c2);
        for(int i = 0; i < 26; i++){
            if(cnt1[i] == 0)continue;
            for(int j = 0; j < 26; j++){
                if(cnt2[j] == 0)continue;

                int t1 = c1, t2 = c2;
                // System.out.printf("%s, %s, %s, %s, %s, %s\n", c1, c2, (char)('a' + i), (char)('a' + j), t1, t2);

                
                if(cnt1[j] == 0)t1++;
                if(cnt1[i] == 1 && j != i)t1--;
                if(cnt2[i] == 0)t2++;
                // System.out.printf("%s, %s, %s, %s, %s, %s\n", c1, c2, (char)('a' + i), (char)('a' + j), t1, t2);

                if(cnt2[j] == 1 && j != i)t2--;
                // System.out.printf("%s, %s, %s, %s, %s, %s\n", c1, c2, (char)('a' + i), (char)('a' + j), t1, t2);
                if(t1 == t2)return true;
            }
        }
        return false;
    }
}

题目四

过桥的时间

做到这道题,还剩 40 分钟,心想还有戏。

然后阅读理解花了 5 分钟。理解题意后,没有思路,直觉告诉我可以用两个优先队列来解决,但是一直到 11:40 了(12 点结束比赛),还是没理顺,最后进入了听天由命,一边 coding 一边想思路的放飞状态,写两句,删两句,改两句,最后自然是 gameover 了。

总结

手速!手速!手速!要手速!

这场比赛前三题都不是很难,所以拼手速很重要。手速上不去,感觉我还是练习的量不够,所以经常陷入没必要纠结、莫名其妙的紧张中。我实在不知道有啥好紧张的。

战胜那 184 位四题大佬或许很难,但是手速提上去,超越 700 来个三题选手,还是有戏的。

其次,平常刷题时,还是要尽可能脱离对测试用例的依赖,脱离对 debugger 工具的依赖,逐渐寻找快递定位问题的感觉。因为我开了会员,所以经常用官方的 debugger 功能。早知道不开了🤣

根据官方说明,并不是每一次都能幸运地看到卡住的用例。

第三,复制在粘贴相似的语句后,一定要把粘贴的那部分从头到尾读一遍,修改里面的变量名,避免因为低阶错误导致的时间黑洞

最后,还是要养成先想清楚,再 coding 的习惯,至少要理顺整体思路再 coding,边写边改真的要不得。

最最后,通关要紧,不要在赛场上纠结茴香豆的 N 种写法

image.png

评论 (21)