How to optimally divide an array into two subarrays so that sum of elements in both are same, otherwise give an error?

前端 未结 22 862
一生所求
一生所求 2020-12-02 11:20

How to optimally divide an array into two subarrays so that sum of elements in both subarrays is same, otherwise give an error?

Example 1

Given the array

相关标签:
22条回答
  • 2020-12-02 12:06

    A non optimal solution in python,

    from itertools import permutations
    
    def get_splitted_array(a):
      for perm in permutations(a):
        l1 = len(perm)
        for i in range(1, l1):
          if sum(perm[0:i]) == sum(perm[i:l1]):
            return perm[0:i], perm[i:l1]
    
    >>> a = [6,1,3,8]
    >>> get_splitted_array(a)
    ((6, 3), (1, 8))
    >>> a = [5,9,20,1,5]
    >>> 
    >>> get_splitted_array(a)
    ((5, 9, 1, 5), (20,))
    >>> 
    
    
    0 讨论(0)
  • 2020-12-02 12:07

    In its common variant, this problem imposes 2 constraints and it can be done in an easier way.

    1. If the partition can only be done somewhere along the length of the array (we do not consider elements out of order)
    2. There are no negative numbers.

    The algorithm that then works could be:

    1. Have 2 variables, leftSum and rightSum
    2. Start incrementing leftSum from the left, and rightSum from the right of the array.
    3. Try to correct any imbalance in it.

    The following code does the above:

    public boolean canBalance(int[] nums) {
      int leftSum = 0, rightSum = 0, i, j;
      if(nums.length == 1)
          return false;
      for(i=0, j=nums.length-1; i<=j ;){
          if(leftSum <= rightSum){
             leftSum+=nums[i];
             i++;
          }else{
             rightSum+=nums[j];
             j--;
          }
      }
      return (rightSum == leftSum);
    }
    

    The output:

    canBalance({1, 1, 1, 2, 1})       → true    OK      
    canBalance({2, 1, 1, 2, 1})       → false   OK      
    canBalance({10, 10})              → true    OK          
    canBalance({1, 1, 1, 1, 4})       → true    OK      
    canBalance({2, 1, 1, 1, 4})       → false   OK      
    canBalance({2, 3, 4, 1, 2})       → false   OK      
    canBalance({1, 2, 3, 1, 0, 2, 3}) → true    OK      
    canBalance({1, 2, 3, 1, 0, 1, 3}) → false   OK      
    canBalance({1})                   → false   OK      
    canBalance({1, 1, 1, 2, 1})       → true    OK
    

    Ofcourse, if the elements can be combined out-of-order, it does turn into the partition problem with all its complexity.

    0 讨论(0)
  • 2020-12-02 12:08

    This is called partition problem. There are optimal solutions for some special cases. However, in general, it is an NP-complete problem.

    0 讨论(0)
  • 2020-12-02 12:08
        def listSegmentation(theList):
        newList = [[],[]]
        print(theList)
    
        wt1 = 0
        wt2 = 0
        dWt = 0
    
        for idx in range(len(theList)):
            wt = theList[idx]
    
            if (wt > (wt1 + wt2) and wt1 > 0 and wt2 > 0):
                newList[0] = newList[0] + newList[1]
                newList[1] = []
                newList[1].append(wt)
                wt1 += wt2
                wt2 = wt 
            elif ((wt2 + wt) >= (wt1 + wt)):
                wt1 += wt
                newList[0].append(wt)
            elif ((wt2 + wt) < (wt1 + wt)):
                wt2 += wt
                newList[1].append(wt)
    
        #Balancing
        if(wt1 > wt2):
            wtDiff = sum(newList[0]) - sum(newList[1])
            ls1 = list(filter(lambda x: x <= wtDiff, newList[0]))
            ls2 = list(filter(lambda x: x <= (wtDiff/2) , newList[1]))
    
            while len(ls1) > 0 or len(ls2) > 0:
                if len(ls1) > 0:
                    elDif1 = max(ls1)
                    newList[0].remove(elDif1)
                    newList[1].append(elDif1)
    
                if len(ls2) > 0:
                    elDif2 = max(ls2)
                    newList[0].append(elDif2)
                    newList[1].remove(elDif2)
    
                wtDiff = sum(newList[0]) - sum(newList[1])
                ls1 = list(filter(lambda x: x <= wtDiff, newList[0]))
                ls2 = list(filter(lambda x: x <= (wtDiff/2) , newList[1]))
    
    
        if(wt2 > wt1):
            wtDiff = sum(newList[1]) - sum(newList[0])
            ls2 = list(filter(lambda x: x <= wtDiff, newList[1]))
            ls1 = list(filter(lambda x: x <= (wtDiff/2) , newList[0]))
            while len(ls1) > 0 or len(ls2) > 0:
                if len(ls1) > 0:
                    elDif1 = max(ls1)
                    newList[0].remove(elDif1)
                    newList[1].append(elDif1)
    
                if len(ls2) > 0:
                    elDif2 = max(ls2)
                    newList[0].append(elDif2)
                    newList[1].remove(elDif2)
    
                wtDiff = sum(newList[1]) - sum(newList[0])
                ls2 = list(filter(lambda x: x <= wtDiff, newList[1]))
                ls1 = list(filter(lambda x: x <= (wtDiff/2) , newList[0]))
                print(ls1, ls2)
    
    
        print(sum(newList[0]),sum(newList[1]))
        return newList
    
    
    #Test cases
    lst1 = [4,9,8,3,11,6,13,7,2,25,28,60,19,196]
    lst2 = [7,16,5,11,4,9,15,2,1,13]
    lst3 = [8,17,14,9,3,5,19,11,4,6,2]
    
    print(listSegmentation(lst1))
    print(listSegmentation(lst2))
    print(listSegmentation(lst3))
    
    0 讨论(0)
  • 2020-12-02 12:10

    @Gal Subset-Sum problem is NP-Complete and has a O(n*TotalSum) pseudo-polynomial Dynamic Programming algorithm. But this problem is not NP-Complete. This is a special case and in fact this can be solved in linear time.

    Here we are looking for an index where we can split the array into two parts with same sum. Check following code.

    Analysis: O(n), as the algorithm only iterates through the array and does not use TotalSum.

    public class EqualSumSplit {
    
        public static int solution( int[] A ) {
    
            int[] B = new int[A.length];
            int[] C = new int[A.length];
    
            int sum = 0;
            for (int i=0; i< A.length; i++) {
                sum += A[i];
                B[i] = sum;
                // System.out.print(B[i]+" ");
            }   
            // System.out.println();
    
            sum = 0;
            for (int i=A.length-1; i>=0; i--) {
                sum += A[i];
                C[i] = sum;
                // System.out.print(C[i]+" ");
            }
            // System.out.println();
    
            for (int i=0; i< A.length-1; i++) {
                if (B[i] == C[i+1]) {
                    System.out.println(i+" "+B[i]);
                    return i;
                }
            }
    
            return -1;
    
        }
    
         public static void main(String args[] ) {
             int[] A = {-7, 1, 2, 3, -4, 3, 0};
             int[] B = {10, 20 , 30 , 5 , 40 , 50 , 40 , 15};        
             solution(A);
             solution(B);
         }
    
    }
    
    0 讨论(0)
  • 2020-12-02 12:11
    a=[int(g) for g in input().split()]     #for taking the array as input in a 
                                         single line
    leftsum=0
    n=len(a)
    for i in range(n):                      
        leftsum+=a[i]                       #calculates the sum of first subarray             
        rightsum=0
        for j in range(i+1):
            rightsum+=a[j]                  #calculates the sum of other subarray
        if leftsum==rightsum:
            pos=i+1                         #if the sum of subarrays are equal, 
            break                           set position where the condition
                                            gets satisfied and exit the loop 
        else:
            pos=-1                          #if the sum of subarrays is not 
                                            equal, set position to -1 
    if pos=-1 or pos=n:
        print('It is not possible.')
    else:                                   #printing the sub arrays`
        for k in range(n):
            if pos=k:
                print('')
            print(str(a[k]),end='')
    
    0 讨论(0)
提交回复
热议问题