[AcWing] 1913. 公平摄影(C++实现)前缀和+哈希表
1. 题目
2. 读题(需要重点注意的东西)
思路:
前缀和
最长的答案可能有如下三种情况:
① 全为 1 (1代表根西岛牛 G )
② 全为 -1 (-1代表荷斯坦牛 H )
③ 1 和 -1 的数量相等(构建前缀和数组,找最长的区间和为 0 的区间)
答案就是要找上述三种情况的最大值,即 res = max(①,②,③)
①②两种情况遍历一遍数组即可,找最大的相同连续串;
第③种情况构建前缀和数组,找最长的区间和为 0 的区间即可。
直接暴力遍历会超时,因此考虑如何优化?
优化:哈希表
哈希表存最早出现的前缀和的下一个位置
如有如下序列,初始化sum = 0定义为前缀和,初始化res = -1为答案,y 为牛的种类,x 为位置,遍历一遍
当sum前缀和相同时,区间和为0(前缀和之差就是区间和),我们要求最长的区间,那么每个前缀和第一次出现的位置中,一定存在答案(贪心),因此我们用哈希表存储前缀和最早出现的位置。
因此,第一次出现sum的下一个位置和最后一次出现sum的位置相减就是答案。
3. 解法
-----------------------------------------------解法:前缀和----------------------------------------------
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 100010;
int n;
PII q[N];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ )
{
int x;
char str[2];
// 用string读取,避免读入空格等无意义符号
scanf("%d%s", &x, str);
if (*str == 'G') q[i] = {x, 1};
else q[i] = {x, -1};
}
// 按照x排序
sort(q + 1, q + n + 1);
// 用哈希表进行优化
unordered_map<int, int> hash;
// 定义答案res,前缀和sum,记录一下当前区间的起点last
int res = 0, sum = 0, last;
for (int i = 1; i <= n; i ++ )
{
// 第③种情况
// 如果当前前缀和没有出现过,将其映射到下标x上(因此哈希表存的是最早出现的前缀和的位置)
// 先判断,再加上当前数求前缀和
if (!hash.count(sum)) hash[sum] = q[i].x;
// 求前缀和
sum += q[i].y;
// 如果当前前缀和存在,那么更新答案
if (hash.count(sum)) res = max(res, q[i].x - hash[sum]);
// 第① ②两种情况,求出最长相同序列的长度
if (i == 1 || q[i].y != q[i - 1].y) last = q[i].x;
res = max(res, q[i].x - last);
}
printf("%d\n", res);
return 0;
}
可能存在的问题
4. 可能有帮助的前置习题
5. 所用到的数据结构与算法思想
- 前缀和