【力扣】第 461 场周赛 AK题解
1. 三段式数组 I
思路:整个数组都要是严格的“先增后减再增”的话,说明不能有前后一样的,且先有一个波峰(a[i] > a[i-1] && a[i] > a[i+1]),后有一个波谷(a[i] < a[i-1] && a[i] < a[i+1])。
查看代码
class Solution {
public:
bool isTrionic(vector<int>& a) {
int up = 0, down = 0, last = 0;
for(int i=1; i+1<a.size(); i++)
{
if(a[i]==a[i-1]||a[i]==a[i+1]) return false;
if(a[i]>a[i-1]&&a[i]>a[i+1]) up++, last = 0;
if(a[i]<a[i-1]&&a[i]<a[i+1]) down++, last = 1;
}
return up==1&&down==1&&last==1;
}
};
2. 平衡装运的最大数量
思路:根据题意贪心即可,遍历到第 i 个元素时,更新序列最大值 ma,如果 a[i] 不等于 ma 的话,说明可以直接划分,cnt++,重置 ma = 0。
查看代码
class Solution {
public:
int maxBalancedShipments(vector<int>& w) {
int ma = 0, cnt = 0;
for(int i=0; i<w.size(); i++)
{
ma = max(ma,w[i]);
if(ma!=w[i])
{
cnt++;
ma = 0;
}
}
return cnt;
}
};
3. 变为活跃状态的最小时间
思路:经典的二分答案模板题。考虑到 t 越大的时候,字符串中的 # 就越多,自然就越容易满足条件。这里就是一个单调性(t 越大 -> 越容易合法),所以对 t 进行二分,每次判断当前二分到的时间 t 能产生多少的带 # 子串。
怎么统计数量呢?考虑有一个字符串 a#aa#a,我们从 1 开始记下标,那么 # 的位置就是 2 和 5。统计的时候,对于第一个 #,包含它但不包含后续 # 的数量就是 2 * (5 - 2) = 6,表示包含第一个 # 的区间,左端点有两种取法,右端点有 (5 - 2 = 3) 种取法。对于第二个 #,同样的,有 5 * 2 = 10 种,所以一共是 6 + 10 = 16 种,这样就不重不漏地找到了所有子串的数量。如果 16 >= k,那么就是合法的,可以继续二分缩小右端点 (r = mid - 1),否则说明太小了要扩大些,即扩大左端点 (l = mid + 1)。
查看代码
class Solution {
public:
using ll = long long;
bool check(int t, vector<int>& order, int k, int n)
{
vector<int> id;
for(int i=0; i<=t; i++) id.push_back(order[i]+1);
sort(id.begin(),id.end());
ll cnt = 0;
for(int i=0; i<id.size(); i++)
{
ll L = id[i], R = (i+1==id.size()?n-id[i]+1:id[i+1]-id[i]);
cnt += L*R;
if(cnt>=k) return true;
}
return false;
}
int minTime(string s, vector<int>& order, int k) {
int n = s.size();
int l = 0, r = n-1, ans = n;
while(l<=r)
{
int mid = (l+r)>>1;
if(check(mid,order,k,n)) ans = mid, r = mid - 1;
else l = mid + 1;
}
return ans==n?-1:ans;
}
};
4. 三段式数组 II
思路:纯模拟就行了。用三个数组 p1 p2 p3,分别记录第一段上升,第二段下降和第三段上升的待判断序列。
- 对于
p1,把当前a[i] > a[i-1]的全 push 进去,如果发现找不到或者当前a[i] == a[i-1],说明不用找了,清空p1,重头来,否则继续搞p2; - 对于
p2,同样的,把a[i] < a[i-1]的一路 push 进去,如果发现相邻相同的,清空p1、p2,重头来,否则继续搞p3; - 对于
p3,和p1一样的逻辑,但是如果发现p3凑不出来,那也是全清空;否则进入判断。
判断:取 p1 最大的后缀和 + p2 全部(去掉和 p1 p3 重合部分)+ p3 的最大的前缀和即是本轮答案。比较更新每次判断的最大值即可。
查看代码
class Solution {
public:
using ll = long long;
ll cal(vector<int> &p){
ll cur = p[0]+p[1], ma = cur;
for(int i=2;i<p.size(); i++) cur += p[i], ma = max(cur,ma);
return ma;
}
ll sol(vector<int> &p1, vector<int> &p2, vector<int> &p3){
reverse(p1.begin(),p1.end());
ll sum = cal(p1);
reverse(p1.begin(),p1.end());
for(int i=1; i+1<p2.size(); i++) sum += p2[i];
sum += cal(p3);
return sum;
}
ll maxSumTrionic(vector<int>& a) {
vector<int> p1,p2,p3;
ll ans = -1e18;
int i = 1;
p1.push_back(a[0]);
while(i<a.size())
{
// up
while(i<a.size()&&a[i]>p1.back()) p1.push_back(a[i]), i++;
if(i>=a.size()||a[i]==p1.back()||p1.size()==1) {
p1.clear();
p1.push_back(a[i]);
i++;
continue;
}
// down
p2.push_back(p1.back());
while(i<a.size()&&a[i]<p2.back()) p2.push_back(a[i]), i++;
if(i<a.size()&&a[i]==p2.back()||p2.size()==1){
p1.clear(),p2.clear();
p1.push_back(a[i]);
i++;
continue;
}
// up
p3.push_back(p2.back());
while(i<a.size()&&a[i]>p3.back()) p3.push_back(a[i]), i++;
if(p3.size()==1) {
p1 = p3; p2.clear(),p3.clear();
i++;
continue;
}
ans = max(ans,sol(p1,p2,p3));
p1 = p3, p2.clear(),p3.clear();
}
return ans;
}
};

浙公网安备 33010602011771号