第一题
本题采用前缀和和hash表的思路来解题:
本题引入一个新的思想就是:以i为最后一位置的所有子数组,
我们所要求解的连续子数组的和为k,所以如上图所示,将在【0,i】区间内求解和为k的组数组的转化为在【0,i-1】区间内,有多少个前缀和=sum【i】-k的个数;
同时hash表的结构为<前缀和,次数>,表示在【0,i-1】区间内前缀和和其出现的次数;
下面来讨论一下详细的细节:
细节一:
前缀和加入到hash表中的时机:
由于dp【i】 = num【i】+dpi【i-1】可知,在计算dp【i】(i位置的元素前缀和)之前,我们的hash表中只存放【0,i-1】的前缀和;
细节二:
不用真的创建一个前缀和数组,我们可以使用sum变量来表示前一个位置的前缀和:
如:dp【i】 = num【i】+sum;
细节三:
如果整个前缀和为k,如下所示,就需要【-1,0】范围的前缀和为sum【i】-k,所以就需要直接在hash表中添加hash【0】 = 1;
故此,代码如下所示:
class Solution { public int subarraySum(int[] nums, int k) { Map<Integer,Integer> hash = new HashMap<Integer,Integer>(); hash.put(0,1); int sum = 0,ret = 0; for(int x:nums){ sum +=x;//计算当前位置的前缀和 ret +=hash.getOrDefault(sum - k,0); hash.put(sum,hash.getOrDefault(sum,0) + 1); } return ret; } }
第二题
本题可以采用前缀积的方法来求解:
如上图所示,我们可以采用前缀积和后缀积的方式来求解:
步骤一:
预处理前缀积和后缀积:
before表是前缀积:before【i】表示在【0,-1】区间内的所有元素的乘积,公式如下:
before【i】=before【i-1】*num【i】;
after表是后缀积:after【i】表示在【i+1,n-1】区间内的所有元素的乘积,公式如下:
after【i】=after【i+1】*num【i】;
步骤二:
前后缀积的使用:
ret = before【i】*after【i】;
细节处理:
before【0】=1 = after【n-1】;
故以此,代码如下:
class Solution { public int[] productExceptSelf(int[] nums) { int n = nums.length ; int[] before = new int[n]; int[] after = new int[n]; before[0] = after[n-1] = 1; for(int i = 1;i<n;i++){ before[i] = before[i-1]*nums[i-1]; } for(int i = n-2;i >= 0;i--){ after[i] = after[i+1]*nums[i+1]; } int[] res = new int[n]; for(int i = 0;i<n;i++){ res[i] = before[i]*after[i]; } return res; } }
第三题:
知识的引入:
一、同余定理:
二:java中余数(负数)的修正:
本题采用前缀和+hash的方法来求解,题目分析如下所示:
不定位置到i位置的数组之和能够被整除,则可以转化为x(某位置元素的前缀和)能够被k整除;
步骤一:
在【0,i-1】区间内,寻找能够被k整除的组数组的元素和的个数;
公式为(sum%k+k)%k;
步骤二:
使用hash表的的结构来记录前缀和的余数个个数;
class Solution { public int subarraysDivByK(int[] nums, int k) { Map<Integer,Integer> hash = new HashMap<Integer,Integer>(); hash.put(0 % k,1); int sum = 0,ret = 0; for(int x:nums){ sum += x; int r = (sum % k +k) % k; ret +=hash.getOrDefault(r,0); hash.put(r,hash.getOrDefault(r,0)+1); } return ret; } }
ps:本次的内容就到这里了,如果大家感兴趣的话就请一件三连哦!!!