Leetcode 第 386 场周赛题解
- Leetcode 第 386 场周赛题解
- 题目1:3046. 分割数组
- 思路
- 代码
- 复杂度分析
- 题目2:3047. 求交集区域内的最大正方形面积
- 思路
- 代码
- 复杂度分析
- 题目3:3048. 标记所有下标的最早秒数 I
- 思路
- 代码
- 复杂度分析
- 题目4:3049. 标记所有下标的最早秒数 II
- 思路
Leetcode 第 386 场周赛题解
题目1:3046. 分割数组
思路
哈希。
用一个哈希表统计数组 nums 中元素的出现次数,若有出现次数大于 2 的元素,则不能分割。
代码
/*
* @lc app=leetcode.cn id=3046 lang=cpp
*
* [3046] 分割数组
*/
// @lc code=start
class Solution
{
public:
bool isPossibleToSplit(vector<int> &nums)
{
unordered_map<int, int> cnt;
for (int &x : nums)
cnt[x]++;
for (auto &[x, count] : cnt)
if (count > 2)
return false;
return true;
}
};
// @lc code=end
复杂度分析
时间复杂度:O(n),其中 n 是数组 nums 的元素个数。
空间复杂度:O(n),其中 n 是数组 nums 的元素个数。
题目2:3047. 求交集区域内的最大正方形面积
思路
枚举两个矩形。
如果矩形有交集,那么交集一定是矩形。求出这个交集矩形的左下角和右上角。
- 左下角横坐标:两个矩形左下角横坐标的最大值。
- 左下角纵坐标:两个矩形左下角纵坐标的最大值。
- 右上角横坐标:两个矩形右上角横坐标的最小值。
- 右上角纵坐标:两个矩形右上角纵坐标的最小值。
知道坐标就可以算出矩形的长和宽,取二者最小值作为正方形的边长。
如果矩形没有交集,那么长和宽是负数,在计算面积前判断。
代码
/*
* @lc app=leetcode.cn id=3047 lang=cpp
*
* [3047] 求交集区域内的最大正方形面积
*/
// @lc code=start
class Solution
{
public:
long long largestSquareArea(vector<vector<int>> &bottomLeft, vector<vector<int>> &topRight)
{
int n = bottomLeft.size();
long long ans = 0LL;
for (int i = 0; i < n - 1; i++)
{
auto &b1 = bottomLeft[i];
auto &t1 = topRight[i];
for (int j = i + 1; j < n; j++)
{
auto &b2 = bottomLeft[j];
auto &t2 = topRight[j];
int w = min(t1[0], t2[0]) - max(b1[0], b2[0]);
int h = min(t1[1], t2[1]) - max(b1[1], b2[1]);
int size = min(w, h);
if (size > 0)
ans = max(ans, (long long)size * size);
}
}
return ans;
}
};
// @lc code=end
复杂度分析
时间复杂度:O(n2),其中 n 是数组 bottomLeft 的元素个数。
空间复杂度:O(1)。
题目3:3048. 标记所有下标的最早秒数 I
思路
题意有点抽象,形象地解释一下:
你有 n 门课程需要考试,第 i 门课程需要用 nums[i] 天复习。同一天只能复习一门课程。
在第 i 天,你可以选择参加第 changeIndices[i] 门课程的考试。考试这一天不能复习。
搞定所有课程的复习+考试,至少要多少天?
二分答案。
答案越大,越能够搞定所有课程,反之越不能。
有单调性,可以二分答案。
代码
/*
* @lc app=leetcode.cn id=3048 lang=cpp
*
* [3048] 标记所有下标的最早秒数 I
*/
// @lc code=start
class Solution
{
public:
int earliestSecondToMarkIndices(vector<int> &nums, vector<int> &changeIndices)
{
int n = nums.size(), m = changeIndices.size();
if (n > m)
return -1;
vector<int> last_t(n);
auto check = [&](int mx) -> bool
{
ranges::fill(last_t, -1);
for (int t = 0; t < mx; t++)
{
last_t[changeIndices[t] - 1] = t;
}
if (ranges::find(last_t, -1) != last_t.end())
{ // 有课程没有考试时间
return false;
}
int cnt = 0;
for (int i = 0; i < mx; i++)
{
int idx = changeIndices[i] - 1;
if (i == last_t[idx])
{ // 考试
if (nums[idx] > cnt)
{ // 没时间复习
return false;
}
cnt -= nums[idx]; // 复习这门课程
}
else
{ // 留着后面用
cnt++;
}
}
return true;
};
int left = n - 1, right = m + 1;
while (left + 1 < right)
{
int mid = (left + right) / 2;
if (check(mid))
right = mid;
else
left = mid;
}
return right > m ? -1 : right;
}
};
// @lc code=end
复杂度分析
时间复杂度:O(mlogm),其中 m 为数组 changeIndices 的长度。二分的时候保证 n≤m,时间复杂度以 m 为主。
空间复杂度:O(n),其中 n 为数组 nums 的长度。
题目4:3049. 标记所有下标的最早秒数 II
思路
题解:二分答案+反悔贪心(Python/Java/C++/Go)