1710.卡车上的最大单元数
题目链接:1710.卡车上的最大单元数
请你将一些箱子装在 一辆卡车 上。给你一个二维数组 boxTypes
,其中 boxTypes[i] = [numberOfBoxesi, numberOfUnitsPerBoxi]
:
numberOfBoxesi
是类型i
的箱子的数量。numberOfUnitsPerBoxi
是类型i
每个箱子可以装载的单元数量。
整数 truckSize
表示卡车上可以装载 箱子 的 最大数量 。只要箱子数量不超过 truckSize
,你就可以选择任意箱子装到卡车上。
返回卡车可以装载 单元 的 最大 总数 。
示例 Sample
示例 1:
**输入:** boxTypes = [[1,3],[2,2],[3,1]], truckSize = 4
**输出:** 8
**解释:** 箱子的情况如下:
- 1 个第一类的箱子,里面含 3 个单元。
- 2 个第二类的箱子,每个里面含 2 个单元。
- 3 个第三类的箱子,每个里面含 1 个单元。
可以选择第一类和第二类的所有箱子,以及第三类的一个箱子。
单元总数 = (1 * 3) + (2 * 2) + (1 * 1) = 8
示例 2:
**输入:** boxTypes = [[5,10],[2,5],[4,7],[3,9]], truckSize = 10
**输出:** 91
提示:
1 <= boxTypes.length <= 1000
1 <= numberOfBoxesi, numberOfUnitsPerBoxi <= 1000
1 <= truckSize <= 106
我的题解
排序贪心即可。
class Solution {
public:
int maximumUnits(vector<vector<int>>& boxTypes, int truckSize) {
sort(boxTypes.begin(), boxTypes.end(), [&](auto a, auto b) { return a[1] > b[1]; });
int ans(0);
for (int i = 0; i < boxTypes.size(); i++) {
int x = min(boxTypes[i][0], truckSize);
ans += boxTypes[i][1] * x;
truckSize -= x;
}
return ans;
}
};
1711.大餐计数
题目链接:1711.大餐计数
大餐 是指 恰好包含两道不同餐品 的一餐,其美味程度之和等于 2 的幂。
你可以搭配 任意 两道餐品做一顿大餐。
给你一个整数数组 deliciousness
,其中 deliciousness[i]
是第 i
道餐品的美味程度,返回你可以用数组中的餐品做出的不同 大餐 的数量。结果需要对 109 + 7
取余。
注意,只要餐品下标不同,就可以认为是不同的餐品,即便它们的美味程度相同。
示例 Sample
示例 1:
**输入:** deliciousness = [1,3,5,7,9]
**输出:** 4
**解释:** 大餐的美味程度组合为 (1,3) 、(1,7) 、(3,5) 和 (7,9) 。
它们各自的美味程度之和分别为 4 、8 、8 和 16 ,都是 2 的幂。
示例 2:
**输入:** deliciousness = [1,1,1,3,3,3,7]
**输出:** 15
**解释:** 大餐的美味程度组合为 3 种 (1,1) ,9 种 (1,3) ,和 3 种 (1,7) 。
提示:
1 <= deliciousness.length <= 105
0 <= deliciousness[i] <= 220
我的题解
有卡常 ……
class Solution {
public:
int countPairs(vector<int>& deliciousness) {
const int maxn = (1 << 21) + 7;
int g[maxn] = {0};
int ans(0);
const int MOD = 1e9 + 7;
const int n = deliciousness.size();
for (int i : deliciousness) g[i]++;
set<int> s;
for (int i : deliciousness) s.insert(i);
for (int i = 1; i <= (1 << 21); (i <<= 1)) {
for (int a : s) {
int b = i - a;
if (a < b)
ans = (ans + g[a] * g[b]) % MOD;
else if (a == b)
ans = (ans + g[a] * (g[b] - 1ll) / 2) % MOD;
}
}
return ans;
}
};
1712.将数组分成三个子数组的方案数
题目链接:1712.将数组分成三个子数组的方案数
我们称一个分割整数数组的方案是 好的 ,当它满足:
- 数组被分成三个 非空 连续子数组,从左至右分别命名为
left
,mid
,right
。 left
中元素和小于等于mid
中元素和,mid
中元素和小于等于right
中元素和。
给你一个 非负 整数数组 nums
,请你返回 好的 分割 nums
方案数目。由于答案可能会很大,请你将结果对 109 + 7
取余后返回。
示例 Sample
示例 1:
**输入:** nums = [1,1,1]
**输出:** 1
**解释:** 唯一一种好的分割方案是将 nums 分成 [1] [1] [1] 。
示例 2:
**输入:** nums = [1,2,2,2,5,0]
**输出:** 3
**解释:** nums 总共有 3 种好的分割方案:
[1] [2] [2,2,5,0]
[1] [2,2] [2,5,0]
[1,2] [2,2] [5,0]
示例 3:
**输入:** nums = [3,2,1]
**输出:** 0
**解释:** 没有好的分割方案。
提示:
3 <= nums.length <= 105
0 <= nums[i] <= 104
我的题解
二分
class Solution {
public:
int waysToSplit(vector<int>& nums) {
const int n = nums.size();
vector<int> s(n);
for (int i = 0; i < n; ++i) {
s[i] = nums[i] + (i ? s[i - 1] : 0);
}
int ans(0);
const int MOD = 1e9 + 7;
for (int i = 0; i < n - 2 && s[i] <= s[n - 1] / 3; i++) {
int l, r;
l = lower_bound(s.begin(), s.end(), s[i] * 2) - s.begin();
l = max(i + 1, l);
r = upper_bound(s.begin(), s.end(), s[i] + (s[n - 1] - s[i]) / 2) - s.begin();
r = min(n - 1, max(r, i + 1));
ans = (ans + r - l) % MOD;
}
return ans;
}
};
双指针(Y总太强啦)。只考虑了 left 和 mid 的分隔,没有单调性。但是,考虑 mid 和 right 的分隔时,left 和 mid 的分隔可以双指针。
class Solution {
public:
int waysToSplit(vector<int>& nums) {
int n = nums.size();
const int mod = 1e9 + 7;
vector<int> s(n + 1);
for (int i = 1; i <= n; i++) s[i] = s[i - 1] + nums[i - 1];
int ans = 0;
for (int i = 3, j = 2, k = 2; i <= n; i++) {
while (s[n] - s[i - 1] < s[i - 1] - s[j - 1]) j++;
while (k + 1 < i && s[i - 1] - s[k] >= s[k]) k++;
if (j <= k && s[n] - s[i - 1] >= s[i - 1] - s[j - 1] && s[i - 1] - s[k - 1] >= s[k - 1])
ans = (ans + k - j + 1) % mod;
}
return ans;
}
};
1713.得到子序列的最少操作次数
题目链接:1713.得到子序列的最少操作次数
给你一个数组 target
,包含若干 互不相同 的整数,以及另一个整数数组 arr
,arr
可能 包含重复元素。
每一次操作中,你可以在 arr
的任意位置插入任一整数。比方说,如果 arr = [1,4,1,2]
,那么你可以在中间添加 3
得到
[1,4, **3** ,1,2]
。你可以在数组最开始或最后面添加整数。
请你返回 最少 操作次数,使得 __target
__ 成为 arr
的一个子序列。
一个数组的 子序列 指的是删除原数组的某些元素(可能一个元素都不删除),同时不改变其余元素的相对顺序得到的数组。比方说,[2,7,4]
是
[4, **2** ,3, **7** ,2,1, **4** ]
的子序列(加粗元素),但 [2,4,2]
不是子序列。
示例 Sample
示例 1:
**输入:** target = [5,1,3], arr = [9,4,2,3,4]
**输出:** 2
**解释:** 你可以添加 5 和 1 ,使得 arr 变为 [ **5** ,9,4, **1** ,2,3,4] ,target 为 arr 的子序列。
示例 2:
**输入:** target = [6,4,8,1,3,2], arr = [4,7,6,2,3,8,6,1]
**输出:** 3
提示:
1 <= target.length, arr.length <= 105
1 <= target[i], arr[i] <= 109
target
不包含任何重复元素。
我的题解
满足唯一性时,LCS(最长公共子序列) 转为 LIS (最长上升子序列)。
知识点++。
class Solution {
public:
int minOperations(vector<int>& target, vector<int>& arr) {
unordered_map<int, int> pos;
for (int i = 0; i < target.size(); i++) pos[target[i]] = i;
vector<int> a;
for (int x : arr) {
if (pos.count(x)) a.emplace_back(pos[x]);
}
int len = 0;
vector<int> q(a.size() + 1);
for (int i = 0; i < a.size(); i++) {
int l = 0, r = len, mid;
while (l < r) {
mid = l + r + 1 >> 1;
if (q[mid] < a[i])
l = mid;
else
r = mid - 1;
}
len = max(len, r + 1);
q[r + 1] = a[i];
}
return target.size() - len;
}
};