Java 在O(n)中,放置两个元素以将阵列平均分成三部分

Java 在O(n)中,放置两个元素以将阵列平均分成三部分,java,algorithm,Java,Algorithm,我遇到了一个问题,让你把两个元素放到一个数组中,使三部分的和相等 Ex: 1 2 4 3 5 2 1 After I drop the 4 and 5, it becomes 1, 2 | 3 | 2, 1 限制条件: 1.Numbers are all integer > 0 2.Drop two elements in the array, so the three splitted subarrays will have same subarray sum.

我遇到了一个问题,让你把两个元素放到一个数组中,使三部分的和相等

  Ex:
  1 2 4 3 5 2 1
  After I drop the 4 and 5, it becomes 1, 2 | 3 | 2, 1
限制条件:

  1.Numbers are all integer > 0

  2.Drop two elements in the array, so the three splitted subarrays will have same subarray sum.
我已经尝试过使用两次通过算法,如下所示

首次通过:O(n) 从左边开始计算累计和,这样我就可以很容易地得到范围和

第二遍:O(n^2) 使用嵌套循环获取子阵列的开始和结束索引。然后,计算左、中、右和

// 1.get accumulated sum map
int[] sumMap = new int[A.length];
int sum = 0;
for(int i = 0; i < A.length; i ++) {
    sum += A[i];
    sumMap[i] = sum;
}

// 2.try each combination
for(int i = 1; i < A.length - 1; i ++) {
    for(int j = i + 1; j < A.length - 1; j ++) {
        int left = sumMap[i] - A[i];
        int mid = sumMap[j] - sumMap[i] - A[j];
        int right = sumMap[A.length - 1] - sumMap[j];

        if(left == mid && mid == right)return true;
    }
}
//1.get累加和映射
int[]sumMap=新的int[A.length];
整数和=0;
for(int i=0;i
有没有更好的算法可以实现O(n)


谢谢

假设不能删除第一个和最后一个元素,并且所有元素都是
>0

将变量
sumlefit
设置为第一个元素的值,将变量
sumlright
设置为最后一个元素的值。您还需要索引变量来记住从左到右的哪些元素已经添加到总和中

  • sumleeft==sumrright
    ,测试是否可以删除左侧和右侧的下一个元素以满足需求。如果是,则->完成。如果不是,则从左侧和右侧取下一个元素,并将其添加到相应的sum变量中。回到1

  • 如果
    sumleeft
    ,则将左侧的下一个值添加到
    sumleeft
    。回到1

  • 如果
    sumleeft>sumrright
    ,则将右侧的下一个值添加到
    sumrright
    。回到1
  • 如果所有元素都被消耗掉,就没有解决方案

    编辑:测试当
    sumleeft==sumlright
    时是否满足要求,可以通过对所有元素进行初始求和(也只需要
    O(n)
    )并检查此和减去要删除的元素是否相等
    sumleeft*3

    • 步骤1:创建和数组

    • 第2步:遵循双指针方法

        public boolean solution(int[] A) {
      
        int leftPointer = 1;
        int rightPointer = A.length - 2;
        int leftPartSum, middlePartSum, rightPartSum;
        int[] sumArray = new int[A.length];
      
        // Initializing the sum array
        sumArray[0] = A[0];
        for(int i = 1; i < A.length; i ++)
            sumArray[i] = sumArray[i-1] +  A[i];
      
        // Using two Pointer technique
        while(leftPointer < rightPointer) {
      
            leftPartSum = sumArray[leftPointer] - A[leftPointer];
            middlePartSum = sumArray[rightPointer] - sumArray[leftPointer] - A[rightPointer];
            rightPartSum = sumArray[A.length - 1] - sumArray[rightPointer];
      
            if(leftPartSum == middlePartSum && middlePartSum == rightPartSum)
                return true;
      
            if (leftPartSum < rightPartSum)
                leftPointer++;
            else if (leftPartSum > rightPartSum)
                rightPointer--;
            else{                   // Else condition denotes: leftPartSum == rightPartSum
                leftPointer++;
                rightPointer--;
            }
        }
        return false; // If no solution is found then returning false
        }
      
      注意:数组包含从0到n-1的索引


      现在,我们将指针向彼此移动,每次移动时,我们都计算leftPartSum、middlePartSum和rightPartSum。我们是否需要移动左指针或右指针取决于两个和中的哪一个(leftPartSum或rightPartSum较小)

      下面的结果更像是一种“粗暴”的方法,也适用于负数。此外,还添加了一个版本,在该版本中,我们可以删除任何2项并按任何索引进行拆分。虽然这只是一个伪代码

      如果数组被我们取出的项目分割

      var count = a.Length (a is input)
      
      // we need:
      for i=0; i<cnt; i++
      sum += a[i]
      sumLeft[i] = a[i]; if (i > 0) sumLeft[i] += sumleft[i-1]
      sumRight[cnt-1-i] = a[i]; if (i > 0) sumRight[cnt-1-i] += sumRight[cnt-1+1-i]
      
      // calc:
      for i=1; i<cnt; i++;
      for j=cnt-2; j>i; j--;
      if (sumLeft[i-1] == sumRight[j+1-1] == sum - a[i] - a[j] - sumLeft[i-1] - sumRight[j-1]) return true;
      
      otherwise return false aft cycle
      
      var count=a.长度(a为输入)
      //我们需要:
      对于i=0;i 0)sumleet[i]+=sumleet[i-1]
      sumRight[cnt-1-i]=a[i];如果(i>0)sumRight[cnt-1-i]+=sumRight[cnt-1+1-i]
      //计算:
      对于i=1;二,;j--;
      如果(sumlefit[i-1]==sumlright[j+1-1]==sum-a[i]-a[j]-sumlefit[i-1]-sumlright[j-1])返回true;
      否则返回假后循环
      
      如果我们可以取出任意2项并在任意位置拆分:

      for i=0; i<cnt; i++
      for j=i+1; j<cnt; j++
      newSum = sum - a[i] - a[j]
      if (newSum mod 3 != 0) continue;
      if passes check(newSum, i, j, a), return true
      
      return false aft cycle
      
      the check (newSum, dropi, dropj, a):
        thirdSum = newSum / 3
      
        // summarize from left, until we get the third'sum - if we exceed it, we don't have a result
        leftSum = 0;
        i=0;
        do {
          if (i != dropi && i !- dropj) leftSum += a[i]
          i++;
        } while leftSum < thirdSum
        if (thirdSum != leftSum) return false;
      
        right = 0;
        i=a.Length-1;
        do {
          if (i != dropi && i !- dropj) rightSum += a[i]
          i++;
        } while rightSum < thirdSum
        if (thirdSum != rightSum) return false;
      
        return true;
      

      表示i=0;我告诉我们你尝试了什么问题描述很模糊。您提供了一个示例,但几乎没有实际提到约束或要求。@jason您对此有最新的解决方案吗?您真的理解他的问题吗?因为我没有。你能解释一下他所指的“三个部分”是什么意思吗?我所理解的是,他有一个数组,以某种方式被分为三部分(他没有解释分割是如何发生的或基于什么)。@AliElgazar如果我理解正确,数组的两个元素被丢弃,它们被丢弃的位置作为分隔符,将数组分割成三个更小的子数组(元素之和相等)向你致敬,先生,从他的帖子里我一点也不明白。干得好。@MichaelButscher我们怎么能这样得到第三个元素?@Danish,你是什么意思,哪一个第三个元素?抱歉,但是根据左半部和右半部来移动指针或向前移动的目的是什么?你能解释一下吗?还有为什么我们不能拿第一个t和最后一个位置?你说没有办法把数组分成3等份,但为什么?请,我想理解它,你能给我解释一下吗?@StuartDTO如果你取第一个元素,你不会把任何元素留在它的左边,因此你能把数组分成的大部分部分是2…除非你去掉最后一个元素例如,如果你使用数组
      [2,4,5,3,3,9,2,2,2]
      ,那么使用第二个和第七个元素将只剩下三个部分:
      [2]
      [5,3,3,9]
      [2,2]
      。当您删除一个元素时,就像您放置了一个假想的分隔符一样。位于第一位或最后一位的分隔符根本不分离任何内容。如果没有额外的空间,您可以在同一数组中使用它,只需计算和,将和除以三,并且每个部分都不能超过和/3值,左指针可以增加一个e每个指针都应该减少每个时间和右指针。一旦子项溢出,这就是中断部分。如果leftSum==rightSum,我们只需要检查sum是否位于{leftPointer+1---righpointer-1}之间,如果这也是相同的,则返回true,否则返回false。这将与接受的答案最终相同一次,而不是求和,我们直接将其乘以3
      for i=0; i<cnt; i++
      for j=i+1; j<cnt; j++
      newSum = sum - a[i] - a[j]
      if (newSum mod 3 != 0) continue;
      if passes check(newSum, i, j, a), return true
      
      return false aft cycle
      
      the check (newSum, dropi, dropj, a):
        thirdSum = newSum / 3
      
        // summarize from left, until we get the third'sum - if we exceed it, we don't have a result
        leftSum = 0;
        i=0;
        do {
          if (i != dropi && i !- dropj) leftSum += a[i]
          i++;
        } while leftSum < thirdSum
        if (thirdSum != leftSum) return false;
      
        right = 0;
        i=a.Length-1;
        do {
          if (i != dropi && i !- dropj) rightSum += a[i]
          i++;
        } while rightSum < thirdSum
        if (thirdSum != rightSum) return false;
      
        return true;