赞
踩
今天学习一下前缀和和哈希表算法思想。主要用于解决连续子数组问题。
前缀和:
给定一个数组a[0,..n-1] 定义Sn=a0+a1+...+an-1。则连续子数组和Suma[i, j] 可以表示为ai+...+aj=Sj-Si-1。即连续子数组和问题可以转换为两个前缀和差。
https://leetcode-cn.com/problems/subarray-sum-equals-k/
给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
想要寻找连续子数组和为k的个数 也就是要寻找有多少Sj-Si=k(0<=i<j-1)成立,在遍历数组过程计算前缀和Sj时可以同时寻找之前是否有前缀和为Sj - k即可。
- public int subarraySum(int[] nums, int k) {
- int count = 0, pre = 0;
- // 哈希表 前缀和 出现次数
- Map<Integer, Integer> mp = new HashMap<>();
- mp.put(0, 1);
- for (int i = 0; i < nums.length; i++) {
- // 数组累加到i时的前缀和
- pre += nums[i];
- // 如果map中含有前缀和-k 则说明已经找到
- if (mp.containsKey(pre - k)) {
- count += mp.get(pre - k);
- }
- // 将该前缀和在map中继续累加
- mp.put(pre, mp.getOrDefault(pre, 0) + 1);
- }
- return count;
- }
https://leetcode-cn.com/problems/subarray-sums-divisible-by-k/
给定一个整数数组 A
,返回其中元素之和可被 K
整除的(连续、非空)子数组的数目。
该题变化点 哈希表存储的是前缀和除以k之后的余数,在遍历数组计算前缀和的过程中 计算当前前缀和除以k余数,如果发现该余数在之前前缀和也出现过 则说明找到。
public int subarraysDivByK(int[] nums, int k) { // 前缀和取余k 个数 Map<Integer, Integer> record = new HashMap<>(); record.put(0, 1); int sum = 0, ans = 0; for (int elem : nums) { sum += elem; // 注意 Java 取模的特殊性,当被除数为负数时取模结果为负数,需要纠正 int modulus = (sum % k + k) % k; int same = record.getOrDefault(modulus, 0); ans += same; record.put(modulus, same + 1); } return ans; }
https://leetcode-cn.com/problems/find-pivot-index/
给你一个整数数组 nums ,请计算数组的 中心下标 。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。
首先计算整个数组的前缀和,依次遍历每一个位置的前缀和,假定当前遍历i 则[0, i-1]前缀和等于[i+1, n-1]之和 则说明找到目标值。
public int pivotIndex(int[] nums) { int presum = 0; // 数组的和 for (int x : nums) { presum += x; } int leftsum = 0; for (int i = 0; i < nums.length; ++i) { // 发现相同情况 if (leftsum == presum - nums[i] - leftsum) { return i; } leftsum += nums[i]; } return -1; }
https://leetcode-cn.com/problems/count-number-of-nice-subarrays/
给你一个整数数组 nums 和一个整数 k。
如果某个 连续 子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」。
请返回这个数组中「优美子数组」的数目。
变化点 哈希表存储前缀和中奇数个数 在遍历数组计算i位置前缀和过程中,如果当前奇数个数-k之前出现过 则说明找到目标值。
public int numberOfSubarrays(int[] nums, int k) { if (nums.length == 0) { return 0; } // 前缀和中奇数个数 HashMap<Integer, Integer> map = new HashMap<>(); //统计奇数个数,相当于我们的 presum int oddnum = 0; int count = 0; map.put(0, 1); for (int x : nums) { // 统计奇数个数 oddnum += x & 1; // 发现存在,则 count增加 if (map.containsKey(oddnum - k)) { count += map.get(oddnum - k); } //存入 map.put(oddnum, map.getOrDefault(oddnum,0) + 1); } return count; }
如果出现连续子数组问题 优先考虑前缀和来解决。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。