题目:来自脑客爱刷题
给定一个无序数组arr,arr中元素可以是正数、负数和0,给定一个整数k,求arr所有子数组中,相加的和为k的最长子数组长度。
解法要求:时间复杂度O(N),额外空间复杂度O(N)
int getSumKMaxSubArrayLength(int* num, int length, int k)
{
if (num == nullptr || length <= 0 || k <= 0)
return -1;
unordered_map<int, int> hashmap;
hashmap.emplace(0, -1);
int sum = 0, len = -1;
for (int i = 0; i < length; i++)
{
sum += num[i];
if (hashmap.find(sum-k) != hashmap.end())//哈希表的查找操作是O(1)
{
if (i - hashmap[sum-k]>len)
len = i - hashmap[sum - k] ;
}
if (hashmap.find(sum) == hashmap.end())
{
hashmap[sum] = i;
}
}
return len;
}
进阶1:给定一个无序数组arr,arr中元素可以是正数、负数和0,求正数和负数的个数相等的最长子数组的长度。
提示:将题目中的正数变成1,负数变成-1,则代入原来题目的代码,求和为0的最长子数组的长度。
int equal_number_of_positive_and_negative(int* num, int length)
{
if (num == nullptr || length <= 0)
return -1;
unordered_map<int, int> hashmap;
hashmap.emplace(0, -1);
int sum = 0, len = -1;
for (int i = 0; i < length; i++)
{
if (num[i]>0)
sum += 1;
else if (num[i]<0)
sum += -1;
if (hashmap.find(sum)!= hashmap.end())//哈希表的查找操作是O(1)
{
if (i - hashmap[sum]>len)
len = i - hashmap[sum];
}
else//if (hashmap.find(sum) == hashmap.end())
{
hashmap[sum] = i;
}
}
return len;
}
进阶2:给定一个无序数组arr,arr中元素只能是0或1,求0和1个数相等的最长子数组的长度。
提示:把数组中的0变成-1,则题目就变成进阶1一样的题目。
进阶3:
题目:EPI
提示:
设数组S,其中S[i]为数组A从0到i位的数的和。
在第i位,有S[i],则需要从S数组的右边开始,寻找第一个小于等于S[i]+k的数,假设这个数是S[j]。则A[i+1:j符合题目的要求——相加之和小于等于k。为了使查找达到O(logn)的时间复杂度,则创建一个有序数组minS,利用二分查找寻找S[j]的下标j。时间复杂度O(nlogn),空间复杂度O(n)。
//在数组arr中小于等于x的数里面,找到其中下标最大那个数的下标
int find_last_smaller_equal_x(const vector<int> &arr, const int x)
{
int len = arr.size(),left=0,right=len-1;
int index = -1;
while (left <= right)
{
if (left == right)
{
if (arr[left]<=x)
index = max(index, left);
break;
}
int mid = left + (right - left) / 2;
if (arr[mid] <= x)
{
index = max(index, mid);
left = mid + 1;
}
else
right = mid - 1;
}
return index;
}
pair<int, int> find_sum_smaller_equal_k(const vector<int> &A,const int k)
{
if (A.empty())
return pair<int, int>(-1,-1);
vector<int> prefix_sum(A.size(), 0);
int sum = 0;
for (int i = 0; i < A.size(); i++)
{
sum += A[i];
prefix_sum[i] = sum;
}
vector<int> min_prefix_sum(prefix_sum);
for (int i = A.size()-2; i>=0; i--)
{
min_prefix_sum[i] = min(min_prefix_sum[i], min_prefix_sum[i + 1]);
}
//第0位的情况特殊,应该先处理
pair<int, int> res(0, -1);
res.second = find_last_smaller_equal_x(min_prefix_sum,k);
for (int i = 0; i < A.size(); i++)
{
int idx = find_last_smaller_equal_x(min_prefix_sum, prefix_sum[i] + k);
if (idx != -1 && idx - i - 1 > res.second - res.first)
{
res.first = i + 1;
res.second = idx;
}
}
return res;
}