第 328 场周赛总结:emo 了
5867
2023.01.15
2023.01.16
发布于 未知归属地
  1. 第一题:虽超级简单,但开局不利

  2. 第二题:简单到不可思议,以至于不断怀疑自己

    1. 更正(于2023.01.16)
  3. 第三题:不难,但一看见就想绕道走

  4. 第四题:终究还是镜中花,水中月

  5. 总结

第一题:虽超级简单,但开局不利

3 分 - 数组元素和与数字和的绝对差

因为检查错误,导致折腾到第 9 分钟才通过,真是恼人(# ̄~ ̄#)。

预料之中地简单。光速无脑写完,奈何死都调试不通,最后发现是 while 条件写错了;:

/*
 * 写错了 while 条件,导致死都不通过
 * */
class Solution {
    public int differenceOfSum(int[] nums) {
        int sum1 = 0, sum2 = 0;
        for(int num: nums){
            sum1 += num;
            sum2 += helper(num);
        }
        return Math.abs(sum1 - sum2);
    }
  
    private int helper(int num){
        int ret = 0;
        while(num / 10 != 0){
            ret += num % 10;
            num = num / 10;
        }
        return ret;
    }
}

第二题:简单到不可思议,以至于不断怀疑自己

4 分 - 子矩阵元素加 1

耗时 7 分钟。

标的是中等题,但是感觉太简单,简单到怀疑自己是不是想错了,或者遗漏了什么关键信息。估算了一下无脑循环的复杂度,发现在 量级而已,应该不会超时,于是忐忑不安地摁下了提交按钮:

class Solution {
    public int[][] rangeAddQueries(int n, int[][] queries) {
        int[][] ret = new int[n][n];
        for(int[] q: queries){
            for(int i = q[0]; i <= q[2]; i++){
                for(int j = q[1]; j <= q[3]; j++ ){
                    ret[i][j] += 1;
                }
            }
        }
        return ret;
    }
}

成功 AC 后,依然觉得不可思议。看来 leecode 这个超时经验值,还是是准确的。

有没有谁知道不暴力的解法?教一下我🤣

更正(于2023.01.16)

因为数学是体育老师教的,而且眼神不好,考场上先是把 queries 的长度上界 10000 看成 1000,还把 算成了 ;下考场后,本帖评论区网友提醒我复杂度算错了,我看了一下,确实算错了,但是我又把 算成了 。哈哈哈,恍恍惚惚红红火火🙃🙃🙃

所以这道题能 AC 纯属侥幸。据说官方会补充用例,所以,我现在好忐忑,我感觉这场我又要回到及格线以下了……

第三题:不难,但一看见就想绕道走

5 分 - 统计好子数组的数目

此题一眼想到思路:滑动窗口 + 计数 + 双指针,数据范围更加让我确信了这一点。这题属于我最不想遇见的题型。

为啥不想遇见呢?因为根据以往经验,每次解滑动窗口的题目,我都不会太顺利,各种边界条件,总是摁下葫芦起了瓢,让人发狂。

于是我本能地跳过了这道题,打算先看看第四题,如果能搞定第四题,剩下的时间再回来解这道题。这样,说不能能四道都通关呢🐒🐒🐒。

然后第四题一不小心,就把时间耗到了 11:48 🙃🙃。然后我绝望地心想:完蛋了。

在最后 10 分钟重新打开了第三题,如同预料中的那样,各种调试不通,答案近在咫尺,但又遥不可及。比赛结束后,绝望地上了个厕所,然后,一直折腾到 13:26 ,才成功 AC。啥也不说了,一图胜千言:

image.png

class Solution {
    public long countGood(int[] nums, int k) {
        int n = nums.length;

        long ret = 0, pairCount = 0;
        Map<Integer, Integer> map = new HashMap<>();
        for(int i = 0, j = 0; i < n; i++){
            int num = nums[i];
            int cnt = map.getOrDefault(num, 0) + 1;
            map.put(num, cnt);
            pairCount += cnt > 0 ? cnt - 1 : 0;
            // System.out.printf("处理右边界:%s, %s, %s, %s, %s\n", i,  j, cnt, pairCount, ret);
            if(pairCount < k)continue;
            ret += n - i;
            // System.out.printf("处理右边界:增加了 %s,变成了%s\n",n - i, ret);


            while(j < i){
                cnt = map.get(nums[j]);
                map.put(nums[j], cnt - 1);
                j++;
                pairCount -= cnt > 0 ? cnt - 1 : 0;
                // System.out.printf("处理左边界:%s, %s, %s, %s, %s\n", i,  j, cnt,pairCount, ret);
                if(pairCount < k)break;
                ret += n - i;
                // System.out.printf("处理左边界:%s\n", ret);

            }
        }
        return ret;
    }
}

第四题:终究还是镜中花,水中月

6 分 - 最大价值和与最小价值和的差值

因为这段时间依然在练习图论的关系,我飘了,我觉的我能搞定这道题。

但是图论中的那些经典算法,和这道题其实没啥关系。n 次 BFS,或者 n 次的 DFS,算法步数都能达到 级别。

最短路径相关的算法,更是不适用于这道题。即便考虑到图中的图是一棵树,任何两个节点之间的路径都是唯一的,所以最短路就是最长路,强行用 n 次单源最短路算法、或者用多源最短路相关算法,复杂度只会比 n 次暴力遍历更高。

直觉告诉我,选择不同根节点时,某些计算结果可以复用,或许可以借助动态规划来解决,但是我不知道怎么进行。假设可以采用某种二元动态规划,节点两两配对,空间复杂度也能达到 级别。

最后,在明知道 n 次 BFS 铁定超时,空间也可能超出限制的情况下,我依然负隅顽抗,写了好几段没有意义的暴力代码,希望能侥幸 AC。最后,当然是一塌糊涂(详见下图中的时间超出和空间超出):

image.png

总结

要相信自己的理性分析。在明知道第四题常规解法会超时的情况下,应该果断放弃,乘着头脑尚且清晰,赶紧去解决第三题。毕竟第三题仔细一点,耐心一点,自己目前的水平是完全能搞定的。好好的上分机会,就这样从自己手里溜走了😭。

2-3 题选手的状态,看来会维持很久,下场比赛要务实一点🤣。刚才去分数预测网站看了一下,这次居然还能涨 31 分,这属实是有点不可思议了。我还以为,这次又要回到及格线以下了(# ̄~ ̄#)

此外,代码跟不上脑子的情况、低级错误、边界处理不当,频频出现,真的还是欠练。我要继续练习去了。

image.png

评论 (60)