通过构建前缀信息来记录最早出现的位置(或最晚出现的位置)是常用的技巧。而前缀信息还有很多
构建种类来解决子数组问题。
1.构建前缀和
vector<int>presum;
void get_prefix(vector<int>nums) {
presum.assign(nums.size() + 1, 0);
for (int i = 1; i < nums.size(); i++) {
presum[i] = presum[i - 1] + nums[i - 1];
}
}
通常presum[i]来表示nums从0~i-1的数的和;presum[0]设为0,防止越界
给定一个数组,求子数组(子数组是连续的)的和为K的最大长度
每当遍历到一个节点时,若求以此节点为结尾的子数组的最大长度时,只需要找到节点之前前缀和为sum-k的节点最早出现的位置,那么以此节点为结尾的子数组的最大长度为i-pre(前缀和为sum-k的节点的下标)。所以从头遍历每个节点当作结尾节点,求出最大值
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int compute(vector<int>nums,int k){
map<int,int>rec;
rec[0]=-1;
int ans=0;
int sum=0;
for(int i=0;i<nums.size();i++){
sum+=nums[i];
if(rec.find(sum-k)!=rec.end())
ans=max(ans,i-rec[sum-k]);
if(rec.find(sum)==rec.end())
rec[sum]=i;
}
return ans;
}
int main() {
int a, b;
cin >> a >> b;
vector<int>nums(a,0);
for(int i=0;i<a;i++)
cin>>nums[i];
cout<<compute(nums,b)<<endl;
return 0;
}
3.和为k的子数组
class Solution {
public:
int comput(vector<int> nums, int k) {
int ans = 0;
int sum = 0;
unordered_map<int, int> rec;
rec[0] = 1;
for (int i = 0; i < nums.size(); i++) {
sum += nums[i];
if (rec.find(sum - k) != rec.end())
ans += rec[sum - k];
rec[sum] += 1;
}
return ans;
}
int subarraySum(vector<int>& nums, int k) { return comput(nums, k); }
};
#include <iostream>
#include <iterator>
#include <vector>
#include <unordered_map>
using namespace std;
void self_reverse(int& i) {
if (i == 0)
i = 0;
else if (i > 0)
i = 1;
else {
i = -1;
}
}
int main() {
int n;
cin >> n;
vector<int>nums(n, 0);
int sum = 0, ans = 0;
unordered_map<int, int>rec;
rec[0] = -1;
for (int i = 0; i < nums.size(); i++) {
cin >> nums[i];
self_reverse(nums[i]);
sum += nums[i];
if (rec.find(sum) != rec.end())
ans = max(ans, i - rec[sum]);
if (rec.find(sum) == rec.end())
rec[sum] = i;
}
cout << ans << endl;
return 0;
}
5.良好时间段
class Solution {
public:
int longestWPI(vector<int>& hours) {
unordered_map<int, int> rec;
rec[0] = -1;
int ans = 0, sum = 0;
for (int i = 0; i < hours.size(); i++) {
sum += hours[i] <= 8 ? -1 : 1;
if (sum > 0)
ans = i + 1;
else {
if (rec.find(sum - 1) != rec.end())
ans = max(ans, i - rec[sum - 1]);
}
if (rec.find(sum) == rec.end())
rec[sum] = i;
}
return ans;
}
};
class Solution {
public:
int minSubarray(vector<int>& nums, int p) {
unordered_map<int, int> rec;
rec[0] = -1;
int allres = 0;
for (int i = 0; i < nums.size(); i++)
allres = ((allres + nums[i]) % p);
if (allres == 0)
return 0;
int partres = 0;
int ans = INT_MAX;
for (int i = 0; i < nums.size(); i++) {
partres = (partres + nums[i]) % p;
if (rec.find((partres - allres + p) % p) != rec.end())
ans = min(ans, i - rec[(partres - allres + p) % p]);
rec[partres] = i;
}
return ans == nums.size() ? -1 : ans;
}
};
7.偶数元音字母数组
class Solution {
public:
int get_path(char c) {
if (c == 'a')
return 0;
else if (c == 'e')
return 1;
else if (c == 'i')
return 2;
else if (c == 'o')
return 3;
else if (c == 'u')
return 4;
else
return -1;
}
int findTheLongestSubstring(string s) {
vector<int> rec(33, -2);
rec[0] = -1;
int ans = 0, cur = 0;
for (int i = 0; i < s.size(); i++) {
int path = get_path(s[i]);
if (path != -1)//如果是-1说明状态不变,但还要继续求长度,因为
//非元音字母也算在其最大长度之中
cur ^= (1 << path);
if (rec[cur] != -2)
ans = max(ans, i - rec[cur]);
else
rec[cur] = i;
}
return ans;
}
};