连续数组(前缀和专题)
目录
🚩了解题意
🚩算法原理
❗为什么hash设置成<0,-1>键值对
❗与和为K的子数组比较hash的键值对
🚩代码实现
🚩了解题意
我们看到给定数组里面只有0和1,我们要找到一个连续的子数组具有相同数量的0和1,那么我们想想,如果我们给0代替成-1,那么-1 1 -1 1是不是等于0是不是相当于找到了具有相同数量的0和1了。
所以 我们首先要想到 将0改成-1 ,然后找到相同的0和1的数量就转换成在数组中最长的子数组中和为0.
这一题和 和为K的子数组 很像 ——和为0的子数组(我们只需要将0改成-1即可)
🚩算法原理
该函数的主要目的是找到nums
中的一个最长的连续子数组,该子数组中0和1的数量相等。它使用了一个哈希表hash
来记录当前累积和首次出现的位置,以便在后续遍历中可以计算当前累积和与首次出现位置之间的距离,从而得到最长的满足条件的子数组长度。
还是利用哈希+前缀和思路。但是这一题我们需要考虑到几个细节。
我们先给过程分析一下吧
- 创建一个无序哈希表
hash
,用于存储累积和及其首次出现的位置。初始化时将累积和为0的位置设为-1,这样方便后续计算。 - 初始化两个整数变量
sum
和ret
,分别用于存储当前累积和和最长满足条件的子数组长度。 - 使用循环遍历
nums
中的每个元素,对累积和进行更新。如果当前元素为0,则累积和加上-1,否则加上1。 - 在每次更新累积和后,检查哈希表中是否已经记录了当前累积和。如果已经记录,则计算当前位置与首次出现位置的距离,并更新最长子数组长度
ret
。否则,将当前累积和及其位置记录到哈希表中。 - 最后,返回最长子数组长度
ret
作为结果。
这段代码的时间复杂度为O(n),其中n是输入向量nums
的长度。
这里有几个细节问题
为什么累积和为0的位置设为-1,我们根据一个情况来阐述吧
<0,-1>键值对,0代表前缀和,-1代表下标。
❗为什么hash设置成<0,-1>键值对
在这段代码中,将累积和为0的位置设为-1的目的是为了在计算最长子数组长度时能够正确处理从数组开头开始的子数组。
在遍历数组时,累积和为0意味着从数组开始到当前位置的子数组中0和1的数量相等。因此,如果在后续的遍历中再次遇到累积和为0,那么说明中间这段子数组中0和1的数量仍然相等。
如果没有将累积和为0的位置设为-1,而是设为0,那么在计算距离时可能会得到错误的结果。因为累积和为0的情况可能出现在数组的第一个位置,此时距离为当前位置减去0,会导致计算出的距离比实际子数组长度小1。
因此,将累积和为0的位置设为-1可以避免这种情况,确保计算出的最长子数组长度是正确的。
❗与和为K的子数组比较hash的键值对
hash[0] = 1
的目的是在处理前缀和时确保能够正确统计到和为k的子数组的数量。这是一个常用的技巧,主要是为了处理当前缀和恰好等于k的情况。
具体来说,hash
这个哈希表用于统计前缀和出现的次数。在初始化时,将累积和为0的次数设置为1是为了确保能够正确处理累积和等于k的情况。
考虑这样一种情况,如果数组中存在一个子数组的和正好等于k,那么这个子数组的前缀和减去k就等于0。因此,在遍历数组时,当遇到一个前缀和sum时,如果之前已经有一个前缀和sum - k存在,那么说明从那个前缀和到当前位置的子数组和正好为k。
举个例子,假设有数组 nums = [1, 2, 3]
,而 k = 3
。在遍历过程中,前缀和依次为1、3、6,此时对于前缀和为3,前缀和为0的情况正好存在,这意味着从数组开头到当前位置的子数组和为3,满足条件。
因此,初始化时将 hash[0] = 1
是为了确保能够正确处理这种情况。
和为K的子数组:<0,1> 在和为K的子数组中0代表前缀和,1代表前缀和出现的次数
和为0的子数组:这一题<0,-1> 在和为0的子数组中 0代表前缀和,-1代表下标的位置。
🚩代码实现
class Solution {
public:
int findMaxLength(vector<int>& nums) {
unordered_map<int,int>hash;
hash[0]=-1;
int sum=0,ret=0;
int dest=0;
for(int i=0;i<nums.size();i++)
{
sum+=nums[i]==0?-1:1;//如果sums[i]==0就改成-1,否则就是1
if(hash.count(sum)) ret=max(ret,i-hash[sum]);
else hash[sum]=i;//这里记录的是长度
}
return ret;
}
};
我们会一直一直在一起哒!