re综合题|双指针
lc986
设双指针i j 遍历两个区间列表
取区间起始max和结束min确定交集
if (start <= end)
res.push_back({start, end});
移动区间结束小指针
最终得到所有区间交集
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
vector<vector<int>> intervalIntersection(vector<vector<int>>& firstList, vector<vector<int>>& secondList)
{
vector<vector<int>> A = firstList, B = secondList;
vector<vector<int>> res;
int i = 0, j = 0;
while (i < A.size() && j < B.size()) {
int start = max(A[i][0], B[j][0]);
int end = min(A[i][1], B[j][1]);
if (start <= end) {
res.push_back({start, end});
}
if (A[i][1] < B[j][1]) { //移动先结束的数组
i++;
} else {
j++;
}
}
return res;
}
};
lc556 逆序思考
先从右往左找第一对升序相邻数字确定需交换的较小数位置 i ;
再从右往左找比 s[i] 大的数位置 j 并交换 s[i] 与 s[j] ;
最后翻转 i+1 到末尾的数字
同时判断结果是否溢出,溢出则返回 -1,否则返回结果
class Solution {
public:
int nextGreaterElement(int n)
{
string s = to_string(n);
int nn = s.size();
// 如果只有1个,直接返回失败
if (nn <= 1)
{
return -1;
}
// 先找到最小的数字, 从n-2开始无必然有数字可以比较
int i = nn - 2;
for (; i >= 0; --i)
{
if (s[i] < s[i+1])
{
break;
}
}
// 数组已经是递增,则无法有更大数,返回失败
if (i < 0)
{
return -1;
}
// 找到比 s[i] 稍大的 数字 s[j]
int j = nn-1;
for (; j >= 0; --j)
{
if (s[j] > s[i])
{
break;
}
}
swap(s[i], s[j]);
// 翻转从i+1到end 的数组
reverse(s.begin()+i+1, s.end());
// 考虑int溢出的情况
long res = stol(s);
return res > INT_MAX ? -1 : res;
}
};
lc532
hash统计数组中各数的出现次数
若 k = 0 ,统计出现至少两次的数的个数;
若 k !=0 ,统计每个数 x 对应的 x + k 也在哈希表中的数的个数
最终得到不同 k-diff 数对的数量
class Solution {
public:
int findPairs(vector<int>& nums, int k) {
unordered_map<int, int> m;
int ans = 0;
for(auto& x : nums)
++m[x];
for(auto& [x,cnt] : m)
{
if(k == 0) // 特判k=0时的情况,需要看一个数是否出现至少两次
ans += (cnt >= 2);
else
ans += (m.count(x+k));
}
return ans;
}
};
没有处理重复右指针的屎山..
被tag双指针欺骗了感情,看来还是要相信自己的判断..
class Solution {
public:
int findPairs(vector<int>& nums, int k) {
sort(nums.begin(),nums.end());
int l=0,r=0,n=nums.size();
int ret=0;
if(n==1) return 0;
while(r<n)
{
r++;
while(l<r && nums[r]-nums[l]>k)
l++;
while(l<r && nums[r]-nums[l]==k)
{
ret++;
l++;
while(l>0 && nums[l]==nums[l-1])
l++;
}
}
return ret;
}
};
lc2234
贪心+sort+双指针+前缀和
先判断花园能否全种满
return max(1LL * (target - 1) * partial + 1LL * (n - 1) * full, 1LL * n * full);
再对不能全满的情况排序后枚举种满的花园数量,计算剩余花朵能让未种满花园达到的最大最小花数
long long avg = (left_flowers + pre_sum) / j;
最终求出花园总美丽值的最大值
long long total_beauty = avg * partial + 1LL * (n - i) * full;
ans = max(ans, total_beauty);
class Solution {
public:
long long maximumBeauty(vector<int>& flowers, long long newFlowers, int target, int full, int partial)
{
int n = flowers.size();
// 如果全部种满,还剩下多少朵花?
long long left_flowers = newFlowers - 1LL * target * n; // 先减掉
for (int& flower : flowers) {
flower = min(flower, target);
left_flowers += flower; // 把已有的加回来
}
// 没有种花,所有花园都已种满
if (left_flowers == newFlowers) {
return 1LL * n * full; // 答案只能是 n*full(注意不能减少花的数量)
}
// 可以全部种满
if (left_flowers >= 0) {
// 两种策略取最大值:留一个花园种 target-1 朵花,其余种满;或者,全部种满
return max(1LL * (target - 1) * partial + 1LL * (n - 1) * full, 1LL * n * full);
}
ranges::sort(flowers); // 时间复杂度的瓶颈在这,尽量写在后面
long long ans = 0, pre_sum = 0;
int j = 0;
// 枚举 i,表示后缀 [i, n-1] 种满(i=0 的情况上面已讨论)
for (int i = 1; i <= n; i++)
{
// 撤销,flowers[i-1] 不变成 target
left_flowers += target - flowers[i - 1];
if (left_flowers < 0) { // 花不能为负数,需要继续撤销
continue;
}
// 满足以下条件说明 [0, j] 都可以种 flowers[j] 朵花
while (j < i && 1LL * flowers[j] * j <= pre_sum + left_flowers)
{
pre_sum += flowers[j];
j++;
}
// 计算总美丽值
// 在前缀 [0, j-1] 中均匀种花,这样最小值最大
long long avg = (left_flowers + pre_sum) / j; // 由于上面特判了,这里 avg 一定小于 target
long long total_beauty = avg * partial + 1LL * (n - i) * full;
ans = max(ans, total_beauty);
}
return ans;
}
};
lcr16
set+双指针
class Solution {
public:
int lengthOfLongestSubstring(string s) {
//!!
if(s.empty()) return 0; // 处理空输入
vector<char> str;
for(char c:s) str.push_back(c);
int left=0,right=0,n=str.size(),len=0;
//unordered_set ret;
unordered_set<char> ret;
while(right<n)
{
//检查
//插入
//更新
while(ret.count(str[right]))
{
ret.erase(str[left]);
left++;
//利用了连续性
//表中 发现了右元素已存在
//要在左边 进行跳过
}
ret.insert(str[right]);
//不存在 就插入
len=max(len,right-left+1);
right++;
}
return len;
}
};