Leetcode 第 395 场周赛题解
Leetcode 第 395 场周赛题解
题目1:3131. 找出与数组相加的整数 I
思路
对两个数组进行排序,相同下标的 nums2[i] - nums1[i] 即为答案。
代码
/*
* @lc app=leetcode.cn id=3131 lang=cpp
*
* [3131] 找出与数组相加的整数 I
*/
// @lc code=start
class Solution
{
public:
int addedInteger(vector<int> &nums1, vector<int> &nums2)
{
ranges::sort(nums1);
ranges::sort(nums2);
return nums2[0] - nums1[0];
}
};
// @lc code=end
复杂度分析
时间复杂度:O(nlogn),其中 n 是数组 nums1 或 nums2 的长度。
空间复杂度:O(1)。
题目2:3132. 找出与数组相加的整数 II
思路
nums1 比 nums2 多两个元素。设 nums2 数组的长度为 n,则数组 nums1 的长度为 n+2。
将两个数组排序后,可以想到,只有 nums1[0…n]、nums1[1…n+1]、nums1[2…n+2] 这三个子数组去与数组 nums2 做比较。
为了使得答案最小,我们先从 nums1[2…n+2] 这个子数组开始比较,设 diff = nums2[0] - nums1[2],然后从下标 idx1 = 2 开始遍历数组 nums1,从下标 idx2 = 0 开始遍历数组 nums2,看是否满足 nums1[idx1] + diff == nums2[idx2]。如果遍历到 nums2 的末尾,发现都满足,则 diff 就是答案;否则,从 nums1[1…n+1] 比较,最后试试 nums1[0…n],题目保证存在答案。
代码
/*
* @lc app=leetcode.cn id=3132 lang=cpp
*
* [3132] 找出与数组相加的整数 II
*/
// @lc code=start
class Solution
{
public:
int minimumAddedInteger(vector<int> &nums1, vector<int> &nums2)
{
ranges::sort(nums1);
ranges::sort(nums2);
for (int i = 2; i > 0; i--)
{
int diff = nums2[0] - nums1[i];
// 在 {nums1[i] + diff} 中找子序列 nums2
int j = 0;
for (int k = i; k < nums1.size(); k++)
{
if (j < nums2.size() && nums2[j] == nums1[k] + diff)
j++;
}
if (j == nums2.size())
return diff;
}
return nums2[0] - nums1[0];
}
};
// @lc code=end
复杂度分析
时间复杂度:O(nlogn),其中 n 为数组 nums1 的长度。瓶颈在排序上。
空间复杂度:O(1)。
题目3:3133. 数组最后一个元素的最小值
思路
位运算。
题解:位运算,两种简洁写法(Python/Java/C++/Go)
代码1
/*
* @lc app=leetcode.cn id=3133 lang=cpp
*
* [3133] 数组最后一个元素的最小值
*/
// @lc code=start
class Solution
{
public:
long long minEnd(int n, int x)
{
n--; // 先把 n 减一,这样下面讨论的 n 就是原来的 n-1
long long ans = x;
// n 的第 j 个比特(从右往左)填到 x 的第 i 个比特上
int i = 0, j = 0;
while (n >> j)
{
// x 的第 i 个比特值是 0,即「空位」
if (((ans >> i) & 01) == 0)
{
// 空位填入 n 的第 j 个比特值
int bit = (n >> j) & 01;
ans |= (long long)bit << i;
j++;
}
i++;
}
return ans;
}
};
// @lc code=end
复杂度分析:
时间复杂度:O(logx+logn)。
空间复杂度:O(1)。
代码2
把 x 取反,用 lowbit 枚举其中的 1,就是要填的空位。
class Solution {
public:
long long minEnd(int n, int x) {
n--;
long long ans = x;
int j = 0;
for (long long t = ~x, lb; n >> j; t ^= lb) {
lb = t & -t;
ans |= (long long) (n >> j++ & 1) * lb;
}
return ans;
}
};
复杂度分析:
时间复杂度:O(logn)。
空间复杂度:O(1)。
题目4:3134. 找出唯一性数组的中位数
思路
二分答案 + 滑动窗口。
二分中位数 upper,问题变成:distinct 值 ≤upper 的子数组有多少个?
设子数组的个数为 cnt,如果 cnt<k 说明二分的 upper 小了,更新二分左边界 left,否则更新二分右边界 right。
怎么计算 distinct 值 ≤upper 的子数组个数 cnt?
由于子数组越长,不同元素个数(distinct 值)不会变小,这样的单调性可以让我们滑窗。
用一个哈希表 freq 统计窗口(子数组)内的元素及其出现次数。
枚举窗口右端点 r,把 nums[r] 加入 freq(出现次数加一)。如果发现 freq 的大小超过 upper,就不断移出窗口左端点元素 nums[l](出现次数减一,如果出现次数等于 0 就从 freq 中移除),直到 freq 的大小 ≤upper 为止。
此时右端点为 r,左端点为 l,l+1,l+2,⋯ ,r 的子数组都是满足要求的(distinct 值 ≤upper),一共有 r−l+1 个,加到子数组个数 cnt 中。
代码
/*
* @lc app=leetcode.cn id=3134 lang=cpp
*
* [3134] 找出唯一性数组的中位数
*/
// @lc code=start
class Solution
{
public:
int medianOfUniquenessArray(vector<int> &nums)
{
int n = nums.size();
long long k = ((long long)n * (n + 1) / 2 + 1) / 2;
auto check = [&](int upper)
{
long long cnt = 0;
int l = 0;
unordered_map<int, int> freq;
for (int r = 0; r < n; r++)
{
freq[nums[r]]++;
while (freq.size() > upper)
{
int out = nums[l++];
freq[out]--;
if (freq[out] == 0)
freq.erase(out);
}
cnt += r - l + 1;
if (cnt >= k)
return true;
}
return false;
};
int left = 0, right = n;
while (left + 1 < right)
{
int mid = (left + right) / 2;
(check(mid) ? right : left) = mid;
}
return right;
}
};
// @lc code=end
复杂度分析
时间复杂度:O(nlogn),其中 n 为数组 nums 的长度。二分 O(logn) 次,每次会跑一个 O(n) 的滑动窗口。
空间复杂度:O(n),其中 n 为数组 nums 的长度。
本文解析了LeetCode第395场周赛中的四个题目,涉及数组相加求整数、数组子数组操作、唯一性数组的中位数计算,以及位运算的应用,提供了详细的思路、代码及复杂度分析。

被折叠的 条评论
为什么被折叠?



