[Leetcode Weekly Contest]333
链接:LeetCode
[Leetcode]2570. 合并两个二维数组 - 求和法
给你两个 二维 整数数组 nums1 和 nums2.
nums1[i] = [idi, vali] 表示编号为 idi 的数字对应的值等于 vali 。
nums2[i] = [idi, vali] 表示编号为 idi 的数字对应的值等于 vali 。
每个数组都包含 互不相同 的 id ,并按 id 以 递增 顺序排列。
请你将两个数组合并为一个按 id 以递增顺序排列的数组,并符合下述条件:
- 只有在两个数组中至少出现过一次的 id 才能包含在结果数组内。
- 每个 id 在结果数组中 只能出现一次 ,并且其对应的值等于两个数组中该 id 所对应的值求和。如果某个数组中不存在该 id ,则认为其对应的值等于 0 。
返回结果数组。返回的数组需要按 id 以递增顺序排列。
遍历即可。
class KeyValuePair{
public int key;
public int value;
public KeyValuePair(int key, int val) {
this.key = key;
this.value = val;
}
}
class Solution {
public int[][] mergeArrays(int[][] nums1, int[][] nums2) {
ArrayList<KeyValuePair> result = new ArrayList<>();
int i=0, j=0;
while(i<nums1.length || j<nums2.length) {
int ind = 0, val = 0;
if(i == nums1.length) {
ind = nums2[j][0];
val = nums2[j][1];
++j;
}
else if(j == nums2.length) {
ind = nums1[i][0];
val = nums1[i][1];
++i;
}
else if(nums2[j][0] < nums1[i][0]) {
ind = nums2[j][0];
val = nums2[j][1];
++j;
}
else if(nums1[i][0] < nums2[j][0]) {
ind = nums1[i][0];
val = nums1[i][1];
++i;
}
else {
ind = nums1[i][0];
val = nums1[i][1] + nums2[j][1];
i++;
j++;
}
if(result.size() == 0 || ind > result.get(result.size()-1).key) result.add(new KeyValuePair(ind, val));
else result.get(result.size()-1).value += val;
}
int[][] res = new int[result.size()][2];
int ind = 0;
for(var pair: result) {
res[ind][0] = pair.key;
res[ind][1] = pair.value;
ind++;
}
return res;
}
}
[Leetcode]2571. 将整数减少到零需要的最少操作数
给你一个正整数 n ,你可以执行下述操作 任意 次:
- n 加上或减去 2 的某个 幂
- 返回使 n 等于 0 需要执行的 最少 操作数。
如果 \(x == 2^i\) 且其中 i >= 0 ,则数字 x 是 2 的幂。
把 n 看成二进制数,那么更高位的比特1 是会受到更低位的比特 1 的加减影响的,但是,最小的比特 1 没有这个约束。
那么考虑优先消除最小的比特 1,设它对应的数字为 lowbit。
消除方法只能是加上lowbit,或者减去 lowbit。
注意,求lowbit可以通过n & -n来得到
class Solution {
public int minOperations(int n) {
if(n == 0) return 0;
int lb = n & -n;
return 1 + Math.min(minOperations(n+lb), minOperations(n-lb));
}
}
[Leetcode]2572. 无平方子集计数
给你一个正整数数组 nums 。
如果数组 nums 的子集中的元素乘积是一个 无平方因子数 ,则认为该子集是一个 无平方 子集。
无平方因子数 是无法被除 1 之外任何平方数整除的数字。
返回数组 nums 中 无平方 且 非空 的子集数目。因为答案可能很大,返回对 \(10^9 + 7\) 取余的结果。
nums 的 非空子集 是可以由删除 nums 中一些元素(可以不删除,但不能全部删除)得到的一个数组。如果构成两个子集时选择删除的下标不同,则认为这两个子集不同。
子集状压 DP。可以枚举 mask 的补集 other 的子集 j,按照「选或不选」的思想,有如下转移:
其中 x 是 mask 对应的 NSQ,cnt[x] 为 x 在 nums 中的出现次数。
class Solution {
private static final int[] PRIMES = new int[]{2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
private static final int MOD = (int) 1e9 + 7, MX = 30, N_PRIMES = PRIMES.length, M = 1 << N_PRIMES;
private static final int[] NSQ_TO_MASK = new int[MX + 1]; // NSQ_TO_MASK[i] 为 i 对应的质数集合(用二进制表示)
static {
for (int i = 2; i <= MX; ++i)
for (int j = 0; j < N_PRIMES; ++j) {
int p = PRIMES[j];
if (i % p == 0) {
if (i % (p * p) == 0) { // 有平方因子
NSQ_TO_MASK[i] = -1;
break;
}
NSQ_TO_MASK[i] |= 1 << j; // 把 j 加到集合中
}
}
}
public int squareFreeSubsets(int[] nums) {
var f = new int[M]; // f[j] 表示恰好组成集合 j 的方案数
f[0] = 1; // 空集的方案数为 1
for (int x : nums) {
int mask = NSQ_TO_MASK[x];
if (mask >= 0) // x 是 NSQ
for (int j = M - 1; j >= mask; --j)
if ((j | mask) == j) // mask 是 j 的子集
f[j] = (f[j] + f[j ^ mask]) % MOD; // 不选 mask + 选 mask
}
var ans = 0L;
for (int v : f) ans += v;
return (int) ((ans - 1) % MOD); // -1 去掉空集
}
}
[Leetcode]2573. 找出对应 LCP 矩阵的字符串
对任一由 n 个小写英文字母组成的字符串 word ,我们可以定义一个 n x n 的矩阵,并满足:
lcp[i][j] 等于子字符串 word[i,...,n-1] 和 word[j,...,n-1] 之间的最长公共前缀的长度。
给你一个 n x n 的矩阵 lcp 。返回与 lcp 对应的、按字典序最小的字符串 word 。如果不存在这样的字符串,则返回空字符串。
对于长度相同的两个字符串 a 和 b ,如果在 a 和 b 不同的第一个位置,字符串 a 的字母在字母表中出现的顺序先于 b 中的对应字母,则认为字符串 a 按字典序比字符串 b 小。例如,"aabd" 在字典上小于 "aaca" ,因为二者不同的第一位置是第三个字母,而 'b' 先于 'c' 出现。
因为要求字典序最小,我们尝试从前往后构造字符串,这样每次填入字典序尽可能小的字符,就能得到字典序最小的答案。
class Solution {
public String findTheString(int[][] lcp) {
int i = 0, n = lcp.length;
var s = new char[n];
for (char c = 'a'; c <= 'z'; ++c) {
while (i < n && s[i] > 0) ++i;
if (i == n) break; // 构造完毕
for (int j = i; j < n; ++j)
if (lcp[i][j] > 0) s[j] = c;
}
while (i < n) if (s[i++] == 0) return ""; // 没有构造完
// 直接在原数组上验证
for (i = n - 1; i >= 0; --i)
for (int j = n - 1; j >= 0; --j) {
int actualLCP = s[i] != s[j] ? 0 : i == n - 1 || j == n - 1 ? 1 : lcp[i + 1][j + 1] + 1;
if (lcp[i][j] != actualLCP) return "";
}
return new String(s);
}
}
参考:LeetCode