/*************************************************************
*给定一个数组全为正数
*求相加和为k的最大子序列的长度
*O(N)时间O(1)空间
*采用滑动窗口的思想,left为当前左边界,right为有边界,组成的窗口为
*要求的sum,判断其和要求的k之间的关系,进行指针的变化
*****************************************************/
#include<iostream>
#include<vector>
#include<algorithm>
#include<unordered_map>
using namespace std;
int getMaxLength(vector<int> &nums,int k) {
int len = nums.size();
if (len==0||k <= 0) return 0; //边界检查
int left = 0, right = 0, maxLen = 0; //得到的最大子数组长度
int sum = nums[0];
while (right < len) {
if (sum == k) {
maxLen = max(right - left + 1, maxLen);
sum -= nums[left++]; //因为数组全为正数,因此当找到后,让left+1位
}
else if (sum < k) {
right++;
if (right == len) break;
sum += nums[right];
}
else
sum -= nums[left++]; //left往右移动
}
return maxLen;
}
int main()
{
vector<int> v = { 2,3,4,1,4,6,8,1,2,4,2 };
cout << getMaxLength(v, 9) << endl; //应该输出4 1,2,4,2
}
上一题的变形
/*************************************************************************************************************
*给定一个无序数组arr,其中元素可正、可负、可0,再给定一个整数k,
*求arr所有的子数组中累加和为k的最长子数组长度。
*分析:无序数组,arr,可正可负可0,求最大累加和为k的子数组的长度
*时间复杂度O(N),需要一个hash_map结构,空间复杂度为O(N)
****************************************************************************************************************/
int getMaxLength1(vector<int> &nums, int k) {
int len = nums.size();
if (len == 0) return 0;
unordered_map<int, int> m; //<key,value>=<累加和,最早出现的位置>
m[0] = -1; // 预处理,0最早出现在-1位置
int maxLen = 0,sum=0;
for (int i = 0; i < len; i++) {
sum += nums[i]; //累加和[0.。。i]
if (m.find(sum - k) != m.end())
maxLen = max(maxLen, i - m[sum - k]);
if (m.find(sum)==m.end()) //注意了,如果没有出现和为sum则,将其加入哈希表中
m[sum] = i;
}
return maxLen;
}
//测试
int main()
{
vector<int> v = { 1,2,3,-2,2,5,6,-3,-3 };
vector<int> v1 = { 5,1,2,3,5 };
cout << getMaxLength1(v1, 5) << endl; //应该输出4 1,2,4,2
}
变形一:
/***************************************
给定一个无序数组arr,其中元素可正、可负、可0,求arr所有的子数组中正数与负数个数相等的最长子数组长度。
分析:问题等价于将正数变为1,负数变为-1,然后就是求取最大累加和等于0的子数组的长度
************************************************************************************************/
int maxLen(vector<int> & nums) {
for (int i = 0; i < nums.size(); i++) {
if (nums[i] < 0) nums[i] = -1;
else if (nums[i] > 0) nums[i] = 1;
}
return getMaxLength1(nums,0); //调用上一个的函数即可。
}
int main()
{
vector<int> v = { 1,2,3,-2,2,5,6,-3,-3 };
vector<int> v1 = { 5,1,2,3,5 };
cout << maxLen(v) << endl; //6
cout << maxLen(v1) << endl; //0
}
变形二:
/************************************************
给定一个无序数组arr,其中元素只是1或0,求arr所有的子数组中0和1个数相等的最长子数组长度
********************************************************************/
int maxLen(vector<int> & nums) {
for (int i = 0; i < nums.size(); i++)
if (nums[i]== 0) nums[i] = -1;
return getMaxLength1(nums,0);
}
int main()
{
vector<int> v = { 1,1,0,0,1,0,0 };
cout << maxLen(v) << endl;
}