[Leetcode Weekly Contest]316

链接:LeetCode

[Leetcode]2446. 判断两个事件是否存在冲突

给你两个字符串数组 event1 和 event2 ,表示发生在同一天的两个闭区间时间段事件,其中:

  • event1 = [startTime1, endTime1] 且
  • event2 = [startTime2, endTime2]

事件的时间为有效的 24 小时制且按 HH:MM 格式给出。
当两个事件存在某个非空的交集时(即,某些时刻是两个事件都包含的),则认为出现 冲突 。
如果两个事件之间存在冲突,返回 true ;否则,返回 false 。

判断即可。

  • 第一个事件的开始时间不晚于第二个事件的结束时间
  • 第二个事件的开始时间不晚于第一个事件的结束时间
class Solution {
    public boolean haveConflict(String[] event1, String[] event2) {
        return !(event2[0].compareTo(event1[1]) > 0 || event2[1].compareTo(event1[0]) < 0);
    }
}

[Leetcode]2447. 最大公因数等于 K 的子数组数目

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 nums 的子数组中元素的最大公因数等于 k 的子数组数目。
子数组 是数组中一个连续的非空序列。
数组的最大公因数 是能整除数组中所有元素的最大整数。

枚举子数组并计算最大公因数即可。注意求数组的最大公约数,可以通过循环传递:
比如:a b c d 的最大公约数是多少
做法:a b 最大公约数 x;用 x 和 c 再取最大公约数 y; 用 y 再去和 d进行最大公约数求取 记为 z。此时 z 就是 a b c d 四个数的最大公约数

class Solution {
    public int subarrayGCD(int[] nums, int k) {
        int n = nums.length, res = 0;
        for(int i=0;i<n;++i) {
            int g = 0;
            for(int j=i;j<n;++j) {
                g = gcd(g, nums[j]);
                if(g%k != 0) break;
                if(g == k) res ++;
            }
        }
        return res;
    }

    public int gcd(int p, int q) {
        if(q == 0) return p;
        return gcd(q, p%q);
    }
}

[Leetcode]2448. 使数组相等的最小开销

给你两个下标从 0 开始的数组 nums 和 cost ,分别包含 n 个 正 整数。
你可以执行下面操作 任意 次:

  • 将 nums 中 任意 元素增加或者减小 1 。
  • 对第 i 个元素执行一次操作的开销是 cost[i] 。

请你返回使 nums 中所有元素 相等 的 最少 总开销。

可通过二分法和前缀和实现。

class Solution {
    public long minCost(int[] nums, int[] cost) {
        HashMap<Integer, Integer> hash = new HashMap<>();
        for(int i=0;i<nums.length;++i) {
            hash.put(nums[i], hash.getOrDefault(nums[i], 0) + cost[i]);
        }
        ArrayList<Map.Entry<Integer, Integer>> entrySet = new ArrayList<>();
        for(var entry:hash.entrySet()) {
            entrySet.add(entry);
        }
        entrySet.sort((s1,s2) -> s1.getKey()-s2.getKey());
        int n = entrySet.size();
        long[] leftSum = new long[n], rightSum = new long[n];
        long cur = 0;
        for(int i=0;i<n;++i) {
            leftSum[i] = cur;
            cur += entrySet.get(i).getValue();
        }
        cur = 0;
        for(int i=n-1;i>=0;--i) {
            rightSum[i] = cur;
            cur += entrySet.get(i).getValue();
        }
        long res = 0;
        for(int i=1;i<n;++i) {
            res += (long)(entrySet.get(i).getKey() - entrySet.get(0).getKey()) * entrySet.get(i).getValue();
        }
        long ans = res;
        for(int i=1;i<n;++i) {
            int diff = entrySet.get(i).getKey() - entrySet.get(i-1).getKey();
            res = res + (long)(leftSum[i]- rightSum[i] - hash.get(entrySet.get(i).getKey())) * diff;
            ans = Math.min(ans, res);
        }
        return ans;
    }
}

[Leetcode] 2449. 使数组相似的最少操作次数

给你两个正整数数组 nums 和 target ,两个数组长度相等。
在一次操作中,你可以选择两个 不同 的下标 i 和 j ,其中 0 <= i, j < nums.length ,并且:

  • 令 nums[i] = nums[i] + 2 且
  • 令 nums[j] = nums[j] - 2 。

如果两个数组中每个元素出现的频率相等,我们称两个数组是 相似 的。
请你返回将 nums 变得与 target 相似的最少操作次数。测试数据保证 nums 一定能变得与 target 相似。

如果把问题中的 +2 和 -2 改成 +1 和 −1,要怎么做?
例如 \(\textit{nums}=[2,8]\)\(\textit{target}=[4,6]\),那么应该让 2 和 4 一对,8 和 6 一对。如果让 2 和 6 一对,8 和 4 一对,是会让变化量的和变得更大的。
通过这种邻项交换法,我们可以证明,让最小的一对,次小的一对,第三小的一对,……,累加每对元素的差的绝对值,就得到了每个数的变化量的和的最小值。
+2 和 -2 会导致无法直接排序然后一一匹配,但注意到 +2 和 -2 并不会改变元素的奇偶性,因此我们可以把偶数分为一组,奇数分为一组,每组分别计算,这样就像 1 那样一一匹配了。
最后把变化量的和除以 4,即为答案。

class Solution {
    public long makeSimilar(int[] nums, int[] target) {
        f(nums);
        f(target);
        var ans = 0L;
        for (var i = 0; i < nums.length; ++i)
            ans += Math.abs(nums[i] - target[i]);
        return ans / 4;
    }

    private void f(int[] a) {
        // 由于元素都是正数,把奇数变成相反数,这样排序后奇偶就自动分开了
        for (var i = 0; i < a.length; ++i)
            if (a[i] % 2 != 0) a[i] = -a[i];
        Arrays.sort(a);
    }
}

参考:LeetCode

posted @ 2022-10-25 20:45  Jamest  阅读(28)  评论(0编辑  收藏  举报