[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