lc1648
lc2271
排序瓷砖区间后用滑动窗口,以每个区间右端点为地毯右端,计算窗口内覆盖的最大长度
class Solution {
typedef long long ll;
public:
int maximumWhiteTiles(vector<vector<int>>& tiles, int carpetLen)
{
ll a = 0, s = 0;
int i = 0, l = carpetLen;
sort(tiles.begin(), tiles.end());
for (auto& v : tiles)
{
int L = v[0], R = v[1];
s += (ll)(R - L + 1);
++int cl = R - l + 1;++
while (i < tiles.size() && tiles[i][1] < cl)
{
s -= (ll)(tiles[i][1] - tiles[i][0] + 1);
i++;
}
ll u = 0;
if (i < tiles.size() && tiles[i][0] < cl)
++u = (ll)(cl - tiles[i][0]);++
a = max(a, s - u);
}
return a;
}
};
本质上是窗口内一块一块加毯子,什么情况下缩短窗口呢,毯子盖不到左边毯子的右侧就缩短,开始扯毯子,窗口的大小是多少呢
(我现在已经把整块左侧项的长度都算进来了,而毯子可能只盖到了左侧项的一部分 那么就要减去之前多加进来的长度)
lc3413
镜像翻转 复用代码
先排序硬币区间,用++滑动窗口算正向最大硬币数++
再反转并转换区间方向二次计算,最终取两次结果的最大值。

#include <vector>
#include <algorithm>
using namespace std;
class Solution {
using ll = long long;
ll f(vector<vector<int>>& t, int l) {
ll a = 0, s = 0;
int i = 0;
for (auto& v : t) {
int L = v[0], R = v[1], c = v[2];
s += (ll)(R - L + 1) * c;
int cl = R - l + 1;
while (t[i][1] < cl) {//find ok_l
s -= (ll)(t[i][1] - t[i][0] + 1) * t[i][2];
i++;
}
ll u = max((ll)(cl - t[i][0]) * t[i][2], 0LL);
a = max(a, s - u);
}
return a;
}
public:
ll maximumCoins(vector<vector<int>>& c, int k) {
sort(c.begin(), c.end());
ll a = f(c, k);
reverse(c.begin(), c.end());
for (auto& v : c) {
int tmp = v[0];
v[0] = -v[1];
v[1] = -tmp;
}
return ++max(a, f(c, k));++
}
};