MENU

子数组累加和为 aim (小于等于 aim) 的三个问题

August 22, 2018 • Read: 3629 • 算法阅读设置

子数组累加和为 aim (小于等于 aim) 的三个问题展开目录

  • 累加和等于 aim 的最长子数组的长度(数组可正可负可零)
  • 累加和等于 aim 的最长子数组的长度(数组只有正数)
  • 累加和小于等于 aim 的最长子数组的长度(数组可正可负可零)

累加和等于 aim 的最长子数组的长度 (数组可 +,-,0)展开目录

这道题我另有文章讲解了,这里就不多说了

累加和等于 aim 的最长子数组的长度(数组只有正数)展开目录

这个和上面唯一的不同就是数组中只有正数,这里使用类似窗口移动的做法,给出两个指针,L,R 表示窗口的左右边界,sum 表示的是 arr [L,R] 之间的累加和,L,R 一直往右动。

  • 如果窗口内 sum <aim,R 就往右扩,并且 sum += arr [R];
  • 如果窗口内 sum > aim,L 就往右扩,并且 sum -= arr [L];
  • 如果窗口内 sum = aim, 就说明这个窗口内累加和为 sum ,此时记录最大值即可;
  • public static int getMax(int[] arr,int aim){
  • if(arr == null || arr.length == 0 || aim < 0)return 0;
  • int L = 0,R = 0;
  • int res = 0, sum = arr[0];
  • while(R < arr.length){
  • if(sum == aim){
  • res = Math.max(res,R - L + 1);
  • sum -= arr[L++];
  • }else if(sum < aim){//小于等于就往右边扩
  • if(++R == arr.length) break;
  • sum += arr[R];
  • }else { // 大于就往左边扩 sum > aim
  • sum -= arr[L++];
  • }
  • }
  • return res;
  • }

累加和小于等于 aim 的最长子数组的长度(数组可 +,-,0)展开目录

两个数组 sum 和 ends,sum [i] 表示的是以 arr [i] 开头 (必须包含 arr [i]) 的所有子数组的最小累加和,对应的 ends [i] 表示的是取得这个最小累加和的右边界。 一开始先求出 sums 数组和 ends [] 数组。
这个题目最精华的是左右边界不回退,就是说,如果从 0 位置扩到 T 区间,T+1 区间不能扩了,此时不是回到 1 位置开始扩,而是舍弃 0 位置,看能不能由于舍弃 0 位置把 T+1 位置加进来:

  • public static int getMaxLength2(int[] arr,int aim){
  • if(arr == null || arr.length == 0)return 0;
  • int[] sums = new int[arr.length]; //以arr[i]开头所有子数组的最小累加和
  • int[] ends = new int[arr.length]; //取得最小累加和的最右边界
  • sums[arr.length-1] = arr[arr.length-1];
  • ends[arr.length-1] = arr.length-1;
  • for(int i = arr.length - 2; i >= 0; i--){ //求出sums数组和ends数组
  • if(sums[i+1] < 0){
  • sums[i] = arr[i] + sums[i+1];
  • ends[i] = ends[i+1];
  • }else {
  • sums[i] = arr[i];
  • ends[i] = i;
  • }
  • }
  • int sum = 0; //目前的累加和 sum -> R
  • int R = 0;//每一次扩到的右边界
  • int res = 0; //答案
  • for(int start = 0; start < arr.length; start++){//每一次开头
  • while(R < arr.length && sum + sums[R] <= aim){//一整块一整块的扩
  • sum += sums[R];
  • R = ends[R] + 1;
  • }
  • sum -= R > start ? arr[start] : 0;//如果R>start,下面start要++了,窗口内减去arr[start]
  • res = Math.max(res,R - start);//窗口是start ~ R-1 ,所以是长度为R-start
  • R = Math.max(R,start + 1); //有没有可能扩不出去
  • }
  • return res;
  • }
Last Modified: October 7, 2018
Archives Tip
QR Code for this page
Tipping QR Code