96 场夜猫双周赛总结,哭晕了
3373
2023.01.21
2023.01.22
发布于 未知归属地
  1. 战果和总体感受

  2. T1:双指针,很简单,但差点没搞定

  3. T2:用优先队列勉强过关过关

    1. 正月初一更新:可以不用开优先队列的,画蛇添足
  4. T3:望而生畏的动态规划题,或者不知道什么题

  5. T4: 非主流图论题

战果和总体感受

第一次参加夜猫双周赛,实在太困了,眼皮都睁不开。盼星星、盼月亮判了一个礼拜的比赛,每天晚上都盼到兴奋的睡不着,临场了却打起了瞌睡…………我是该哭还是该笑😭

很独特的体验,毕竟是大年三十的晚上。

这场比赛也太难了,勉强做对了前两道,被罚时四次,太打击信心了……

去分数预测网站看了一下,这次要降8 分,我真的哭死了,再也不要晚上比赛了。

T1:双指针,很简单,但差点没搞定

简单题,但又是双指针题,我真的瑟瑟发抖。

我和双指针命中犯克。

每次这种双指针题,都要调试老半天处理边界情况,再加上中途 nums1、nums2、i、j 看的眼花,写着写着就写混了,调试了半个小时勉强过关。

下次吸取教训,如果第一题开局不利,这场比赛果断不提交,扣分的感觉好难受😭

代码都不好意思贴了,自己看着想吐:

/**
性能啊、可读性、代码简洁度啊,我已经不 care 了,能 AC 就行
*/
class Solution {
    public int getCommon(int[] nums1, int[] nums2) {
        int m = nums1.length, n = nums2.length;

        int i = 0, j = 0;
        while(i < m && j < n){

            while(nums1[i] < nums2[j]) {
                if(++i > m - 1)return -1;
            }
            if(nums1[i] == nums2[j]) return nums1[i];
            while(nums2[j] < nums1[i]){
                if(++j > n - 1)return -1;
            }
            if(nums1[i] == nums2[j])return nums1[i];
        }

        return -1;

    }

    public static void main(String[] args) {
        int a = new Solution().getCommon(new int[]{1, 6}, new int[]{2,3,4,5});
        System.out.println(a);
    }
}

T2:用优先队列勉强过关过关

说实话,我一开始这连这道题也看不懂。但是剩下的两道,瞄两眼不是我能搞定的,果断回来啃第二题。

考虑到每次操作都不会改变数组和,且每个数只可能增大 k 或者减小 k,所以两个数组对应位置的差,必须能整除 k,且所有的差的和必须是 0;

然后开一个小顶堆,一个大顶堆,依次取堆顶玩消除。

时间复杂度,我实在估算估算不出来,太困了。但是直觉告诉我应该不会 TLE。比较蛋疼的有两个点:

  1. k 可以是 0,这个真的把我恶心到了,导致我罚时 5 分钟。
  2. 有连个用例死都通不过,但是没给出用例。最后发现是整数溢出了,真的好想打我自己。因此又被罚时两次,绝望。

代码很丑,大家不要笑我,毕竟能 AC,我已经很知足了:

class Solution {
    public long minOperations(int[] nums1, int[] nums2, int k) {
        int n = nums1.length;
        long ret = 0, sum = 0;
        int[] diffs = new int[n];
        PriorityQueue<Integer> pqPos = new PriorityQueue<>((o1, o2)->o2-o1);
        PriorityQueue<Integer> pqNeg = new PriorityQueue<>(); 
        for(int i = 0; i < n; i++){
            int diff = nums1[i] - nums2[i];
            if(k == 0){
                if(diff != 0)return -1;
                continue;
            }
            if(diff % k != 0)return -1;
            
            diffs[i] = diff / k;
            sum += diff;
            
            if(diff > 0)pqPos.offer(i);
            if(diff < 0)pqNeg.offer(i); 
        }
        
        if(k == 0)return 0;
        
        if(sum != 0)return -1;
        
        while(!pqNeg.isEmpty() && !pqPos.isEmpty()){
            int posId = pqPos.poll(), negId = pqNeg.poll();
            int pos = diffs[posId], neg = diffs[negId];
            int count = Math.min(pos, -neg);
            diffs[posId] -= count;
            diffs[negId] += count;
            ret += count;
            if(diffs[posId] > 0) pqPos.offer(posId);
            if(diffs[negId] < 0) pqNeg.offer(negId);
        }
        
        return ret;
    }
}

正月初一更新:可以不用开优先队列的,画蛇添足

昨晚赛场上完全慌了,只想着第二题必须通过,然后患得患失,胡乱提交🤣。

其实这个优先队列完全是画蛇添足。

我在赛场上也担心过,用队列模拟,会不会导致超时,我当时没有答案,只是提交撞运气。现在想来,完全可能会超时:假设 k 是 1,然后第一个数相差无穷大,剩下的数相差 -1,这样肯定会超时。这此经历再次说明:没想清楚千万不要动手。

的代码如下:

class Solution {
    public long minOperations(int[] nums1, int[] nums2, int k) {
        int n = nums1.length;
        
        if(k == 0){
            for(int i = 0; i < n; i++) if(nums1[i] != nums2[i]) return -1;
            return 0;
        }
        
        long posSum = 0, sum = 0;
        for(int i = 0; i < n; i++){
            int diff = nums1[i] - nums2[i];
            
            if(diff % k != 0)return -1;
            diff /= k;
            if(diff > 0)posSum += diff;
            sum += diff;
        }
        
        return sum == 0 ? posSum : -1;
    }
}

T3:望而生畏的动态规划题,或者不知道什么题

估计再给我四个小时,我能想出状态转移方程。┓( ´∀` )┏

或者根本不是用动态规划做。

T4: 非主流图论题

瞬间感觉这段时间图论白学了。这道题居然来了个无限网格。好家伙,你都无限了,你让我辛苦学的 BFS、DFS、并查集、最短路、生成树,面子往哪里搁?┓( ´∀` )┏

做完第二题,只剩 20 分钟了,我盯着这道题发呆到 12 点。

直觉告诉我,四种移动方向的坐标,里面有某种玄机,但是天知道是什么玄机。

睡了睡了。

评论 (44)