Leetcode 第 404 场周赛题解
Leetcode 第 404 场周赛题解
题目1:3200. 三角形的最大高度
思路
枚举第一行是红色还是蓝色,再按题意模拟即可。
代码
/*
* @lc app=leetcode.cn id=3200 lang=cpp
*
* [3200] 三角形的最大高度
*/
// @lc code=start
class Solution
{
public:
int maxHeightOfTriangle(int red, int blue)
{
if (red <= 0 || blue <= 0)
return 0;
return max(helper(red, blue), helper(blue, red));
}
// 辅助函数
int helper(int x, int y)
{
int level = 0;
while (x >= 0 && y >= 0)
{
if (level % 2 == 0)
{
x -= (level + 1);
if (x < 0)
break;
}
else
{
y -= (level + 1);
if (y < 0)
break;
}
level++;
}
return level;
}
};
// @lc code=end
复杂度分析
时间复杂度:O(min(sqrt(red), sqrt(blue)))。
空间复杂度:O(1)。
题目2:3201. 找出有效子序列的最大长度 I
思路
全奇数、全偶数、奇偶交替三种情况的最大值即为所求。
代码
/*
* @lc app=leetcode.cn id=3201 lang=cpp
*
* [3201] 找出有效子序列的最大长度 I
*/
// @lc code=start
class Solution
{
public:
int maximumLength(vector<int> &nums)
{
// 分三种情况:全奇、全偶、奇偶交替
int odd = 0, even = 0;
for (int &num : nums)
{
if (num % 2)
odd++;
else
even++;
}
int interlaced = 1, tag = nums[0];
for (int i = 1; i < nums.size(); i++)
if ((nums[i] & 1) ^ (tag & 1))
{
interlaced++;
tag = nums[i];
}
return max(interlaced, max(odd, even));
}
};
// @lc code=end
复杂度分析
时间复杂度:O(n),其中 n 是数组 nums 的长度。
空间复杂度:O(1)。
题目3:3202. 找出有效子序列的最大长度 II
思路
本题是选与不选的子序列问题,可以尝试给出这样的状态定义:
dp[i][j]:以 nums[i] 结尾模 k 后值为 j 的最长子序列的长度。
那么状态转移方程是怎样的呢?对于每一个 i,遍历 j(0<=j<i),dp[i][(nums[i] + nums[j]) % k] = dp[j][(nums[i] + nums[j]) % k] + 1,保证模 k 后的值相同。
代码
/*
* @lc app=leetcode.cn id=3202 lang=cpp
*
* [3202] 找出有效子序列的最大长度 II
*/
// @lc code=start
class Solution
{
public:
int maximumLength(vector<int> &nums, int k)
{
int n = nums.size();
// dp[i][j]: 以 nums[i] 结尾模 k 后值为 j 的最长子序列的长度
vector<vector<int>> dp(n, vector<int>(k, 0));
// 初始化
for (int i = 0; i < n; i++)
dp[i][0] = 1;
int ans = 1;
// 状态转移
for (int i = 1; i < n; i++)
for (int j = 0; j < i; j++)
{
dp[i][(nums[i] + nums[j]) % k] = dp[j][(nums[i] + nums[j]) % k] + 1;
ans = max(ans, dp[i][(nums[i] + nums[j]) % k]);
}
return ans;
}
};
// @lc code=end
复杂度分析
时间复杂度:O(n2),其中 n 是数组 nums 的长度。
空间复杂度:O(n*k),其中 n 是数组 nums 的长度。
题目4:3203. 合并两棵树后的最小直径
思路
代码
/*
* @lc app=leetcode.cn id=3203 lang=cpp
*
* [3203] 合并两棵树后的最小直径
*/
// @lc code=start
class Solution
{
private:
// 求树的直径
int diameter(vector<vector<int>> &edges)
{
vector<vector<int>> g(edges.size() + 1);
for (auto &e : edges)
{
int x = e[0], y = e[1];
g[x].push_back(y);
g[y].push_back(x);
}
int res = 0;
auto dfs = [&](auto &&dfs, int x, int fa) -> int
{
int max_len = 0;
for (auto y : g[x])
{
if (y != fa)
{
int sub_len = dfs(dfs, y, x) + 1;
res = max(res, max_len + sub_len);
max_len = max(max_len, sub_len);
}
}
return max_len;
};
dfs(dfs, 0, -1);
return res;
}
public:
int minimumDiameterAfterMerge(vector<vector<int>> &edges1, vector<vector<int>> &edges2)
{
// 设树 1 的长度为 d1
int d1 = diameter(edges1);
// 设树 2 的长度为 d2
int d2 = diameter(edges2);
// 答案为三种情况的最大值:
// 1. d1
// 2. d2
// 3. 连接两棵树的直径中点,(d1 + 1) / 2 + (d2 + 1) / 2 + 1
return max(max(d1, d2), (d1 + 1) / 2 + (d2 + 1) / 2 + 1);
}
};
// @lc code=end
复杂度分析
时间复杂度:O(n+m),其中 n 是数组 edges1 的长度,m 是数组 edges2 的长度。
空间复杂度:O(n+m),其中 n 是数组 edges1 的长度,m 是数组 edges2 的长度。