1. 使用累加和
顾名思义就是使用累加数组sums[i]
,每个位置上的元素就是此位置及前面所有元素之和。然后针对其中的每个元素right
,求它与前面每个元素left
之差,这个差就是中间元素right-left
的和。这样就能求得所有的可能解:
public int subarraySum(int[] nums, int k) {
int[] sums = new int[nums.length];
sums[0] = nums[0];
int count = 0;
for(int i=1; i < nums.length; ++i) {
sums[i] = sums[i-1]+ nums[i]; //先求和
if(sums[i] == k) {count++;} //每个和本身有可能就是k,所以先统计
}
for (int i = 1; i < sums.length; ++i) {
for (int j = 0; j < i; ++j) {
if (sums[i] - sums[j] == k) { //再求和为k的情况
count++;
}
}
}
return nums[0] == k ? count+1 : count; //查看第一个数字是不是本身是K
}
当然与此类似的一种思路就是不使用这个累加数组,而是使用双指针start
和end
,然后通过不断计算start
和end
之间的和来计数,然后迭代end
到最后。这样就不需要额外的存储空间,而时间复杂度也没有改变O(n2)。
2. 采用哈希表
其实这种思路是上面那种思路的优化,我们看后面的那个双重循环我们是怎么判断的,我们使用双指针然后判断两个和的差值是不是k,那么我们是不是可以换个思路。我们不一个个的判断两个和的差值,而是使用一个和减去k得到另一个“和”,看看这个“和”是不是我们求过的和,如果是那么说明是存在的。
所以我们就得到了解决方法,我们将所有的和放到一个哈希表里,然后对于每个和sum
我们求minus = sum-k
,然后看minus
是否存在于哈希表中,如果存在则让count
加1。下面看一下代码:
public int subarraySum(int[] nums, int k) {
int count = 0, sum = 0;
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0, 1);
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
if (map.containsKey(sum - k)) //求得一个预期的"和",看看它是否存在于哈希表中
count += map.get(sum - k);
map.put(sum, map.getOrDefault(sum, 0) + 1);//然后将新的和放到哈希表中
}
return count;
}