A 判别首字母缩略词
签到题…
class Solution {
public:
bool isAcronym(vector<string> &words, string s) {
string pf;
for (auto &s: words)
pf.push_back(s[0]);
return pf == s;
}
};
B k-avoiding 数组的最小总和
贪心:从 1 1 1开始升序枚举,判断当前数是否可以放入数组,同时维护当前数组中的数,直到找到 n n n个数。
class Solution {
public:
int minimumSum(int n, int k) {
set<int> vis;
int s = 0;
for (int i = 1; vis.size() < n; i++) {
if (vis.count(k - i))
continue;
vis.insert(i);
s += i;
}
return s;
}
};
C 销售利润最大化
动态规划+树状数组:首先将 o f f e r s offers offers按 s t a r t i start_i starti升序排序,枚举 o f f e r s offers offers中的元素,设 p [ i ] p[i] p[i]为销售的最右区间的右端点为 i i i的情况下能够得到的最大利润,设当前元素为 [ l , r , g ] [l, r, g] [l,r,g],则可以更新状态: p [ r ] = m a x { p [ r ] m a x { p [ k ] ∣ 0 ≤ k ≤ l − 1 } + g p[r]=max\left\{\begin{matrix} p[r] \\ max\{p[k] \;|\; 0\le k \le l-1 \} + g \end{matrix}\right. p[r]=max{p[r]max{p[k]∣0≤k≤l−1}+g
利用树状数组来维护前缀上的极大值。
class Solution {
public:
int maximizeTheProfit(int n, vector<vector<int>> &offers) {
N = n + 5;
a = vector<int>(N, 0);
sort(offers.begin(), offers.end());
int res = 0;
for (auto &it: offers) {
int l = it[0] + 1, r = it[1] + 1, g = it[2];//树状数组中下标从1开始
int cur = query(l - 1) + g;//查询前缀极大值
res = max(res, cur);
update(r, cur); //树状数组更新
}
return res;
}
int N;
vector<int> a;//树状数组
inline int lowbit(int x) {
return x & -x;
}
void update(int loc, int val) {// li[loc]=max(li[loc], val);
for (; loc < N; loc += lowbit(loc))
a[loc] = max(a[loc], val);
}
int query(int loc) {// max{li[k] | 1<=k<=loc}
int res = 0;
for (; loc > 0; loc -= lowbit(loc))
res = max(res, a[loc]);
return res;
}
};
D 找出最长等值子数组
二分+哈希:用二分查找答案 l e n len len,这样问题就变成了:判断从 n u m s nums nums 中删除最多 k k k 个元素后,是否存在长为 l e n len len 的等值子数组。设 l o c [ v ] loc[v] loc[v]为 n u m s nums nums中所有 v v v所在下标组成的升序数组,若存在 0 ≤ i ≤ i + l e n − 1 < l o c [ v ] . s i z e ( ) 0\le i \le i+len-1 < loc[v].size() 0≤i≤i+len−1<loc[v].size() 使得 l o c [ v ] [ i + l e n − 1 ] − l o c [ v ] [ i ] + 1 − l e n ≤ k loc[v][i + len - 1] - loc[v][i] + 1 - len \le k loc[v][i+len−1]−loc[v][i]+1−len≤k,则说明可以得到长为 l e n len len 的值为 v v v的等值子数组,枚举 n u m s nums nums中不同的数,即可判断是否可以得到长为 l e n len len 的等值子数组。
class Solution {
public:
int longestEqualSubarray(vector<int> &nums, int k) {
int n = nums.size(), l = 1, r = n;
unordered_map<int, vector<int>> loc;
for (int i = 0; i < n; i++)
loc[nums[i]].push_back(i);
auto can = [&](int len) {//判断是否可以得到长为len的等值子数组
int find = 0;
for (auto &[_, vec]: loc) {//枚举不同的数
for (int i = 0; i + len - 1 < vec.size(); i++)
if (vec[i + len - 1] - vec[i] + 1 - len <= k)
return true;
}
return false;
};
while (l < r) {//二分查找答案
int mid = (l + r + 1) / 2;
if (can(mid))
l = mid;
else
r = mid - 1;
}
return l;
}
};