Drop two elements to split the array to three part evenly in O(n)

前端 未结 3 2030
迷失自我
迷失自我 2021-02-07 19:07

I encounter a problem to let you drop two elements in an array to make the three part\'s sum equal.

  Ex:
  1 2 4 3 5 2 1
  After I drop the 4 and 5, it becomes          


        
相关标签:
3条回答
  • 2021-02-07 19:44

    The results below are more a "brute" approach, should work for negative numbers as well. Also a version where we can remove any 2 items and split by any index is added. although it's just a pseudo code.

    if the array is split by those items we take out...

    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
    

    if we can take out any 2 items and split in any position:

    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;
    
    0 讨论(0)
  • 2021-02-07 19:47
    • Step 1: Create a sum array

    • Step 2: Follow two pointer approach

        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
        }
      

    Detailed Explanation:

    Sum Array: In the first pass over array, count the accumulated sum from the left to right. Althought this will take O(n) time to create a sum array but this will help you in getting the leftPartSum, middlePartSum and rightPartSum in O(1) at any given time.

    Two Pointer Approach: In two pointer approach, One pointer starts from the beginning while the other pointer starts from the end.

    In this case, If we remove the first element or last element, then there is no way in which we can split the array into 3 equal parts. Hence, we can safely assume that

    int leftPointer = 1; 
    int rightPointer = A.length - 2;
    

    Note: Array contains indexed from 0 to n-1;

    Now, we move the pointer towards each other and at every movement we calculate leftPartSum, middlePartSum and rightPartSum. Whether we need to move left pointer or right pointer is decided by the fact that which one of the two sums (leftPartSum or rightPartSum is smaller)

    0 讨论(0)
  • 2021-02-07 19:58

    Assuming that first and last element can't be dropped and all elements are >0:

    Set a variable sumleft to value of first element, sumright to value of last element. You also need index variables to remember which elements from left and right were already added to the sums.

    1. If sumleft == sumright, test if next elements from left and right can be dropped to fulfill requirement. If so -> done. If not take next elements from left and right and add it to the respective sum variable. Back to 1.

    2. If sumleft < sumright, add next value from the left to sumleft. Back to 1.

    3. If sumleft > sumright, add next value from the right to sumright. Back to 1.

    If all elements were consumed, there is no solution.

    Edit: Testing if requirement is fulfilled when sumleft == sumright can be done by initially summing up all elements (also needs only O(n)) and checking if this sum minus the elements to drop is equal sumleft * 3.

    0 讨论(0)
提交回复
热议问题