Equal partitioning with minimum difference in sum - Algorithms and Problem SolvingAlgorithms and Problem Solving


Equal partitioning with minimum difference in sum - Algorithms and Problem SolvingAlgorithms and Problem Solving
Given an array consisting of N Numbers.
Divide it into two Equal partitions (in size both contains N/2 elements) such that difference between sum of both partitions is minimum. If number of elements are odd difference in partition size can be at most 1.
The problem is a specialization of SubSet Sum problem which decides whether we can find any two partition that has equal sum. This is an NP-Complete problem.
But, the problem in question asking for 2 such equal partition where the equality holds when we satisfy following two conditions:
  • Size of the partitions differ by at most 1
  • Sum of the elements in the partitions is minimum
Our goal is to find suboptimal solution with best approximation ratio. Idea is to partition the array in pairs of element that would distribute the sum as uniformly as possible across the partitions. So, each time we would try to take 2 pairs and put one pair in a partition and the other pair in the other partition.
  • Sort the array
  • If number of elements in less than 4 then create partitions accordingly for each cases when we have 1 element or 2 element or 3 element in the array.
  • Otherwise we will take 2 pair each time and put into two partition such that it minimizes the sum diff.
  • Pick the pair(largest, smallest) elemets in the the sorted array and put it to the smaller (wr.to sum) partition.
  • Then pick the second largest element and find its buddy to put them in the ‘other’ partition such that sum of second largest and its buddy minimizes the sum difference of the partitions.
  • The above approach will give a suboptimal solution. The problem in NP complete so, we can’t have an optimal solution but we can improve the approximation ratio as follows.
  • If we have suboptimal solution (ie. sum diff != 0) then we try to improve the solution by swapping a large element in the larger partition with a small element in the smaller partition such that the swap actually minimizes the sum diff.
The O(n^2) time and O(n) space implementation of the above approach is as follows –

//overall O(n^2) time and O(n) space solution using a greedy approach
public static ArrayList<Integer>[] findEqualPartitionMinSumDif(int A[]){
 //first sort the array - O(nlgn)
 Arrays.sort(A);
 ArrayList<Integer> partition1 = new ArrayList<Integer>();
 ArrayList<Integer> partition2 = new ArrayList<Integer>();
 
 //create index table to manage largest unused and smallest unused items
 //O(n) space and O(nlgn) time to build and query the set
 TreeSet<Integer> unused = new TreeSet<>();
 for(int i = 0; i<A.length; i++){
  unused.add(i);
 }
 
 int i = 0;
 int j = A.length-1;
 int part1Sum = 0;
 int part2Sum = 0;
 int diffSum = 0;
 
 //O(n^2) processing time
 while(unused.size() > 0){
  i = unused.first();
  j = unused.last();
  diffSum = part1Sum-part2Sum;
  
  //in case of size of the array is not multiple of 4 then we need to process last 3(or 2 or 1)
  //element to assign partition. This is special case handling
  if(unused.size() < 4){
   switch(unused.size()){
    case 1: 
     //put the 1 remaining item into smaller partition
     if(diffSum > 0){
      partition2.add(A[i]);
      part2Sum += A[i];
     }
     else{
      partition1.add(A[i]);
      part1Sum += A[i];
     }
    break;
    case 2:
     //among the remaining 2 put the max in smaller and min in larger bucket
     int max = Math.max(A[i], A[j]);
     int min = Math.min(A[i], A[j]);
     if(diffSum > 0){
      partition2.add(max);
      partition1.add(min);
      part2Sum += max;
      part1Sum += min;
     }
     else{
      partition1.add(max);
      partition2.add(min);
      part1Sum += max;
      part2Sum += min;
     }
    break;
    case 3:
     //among the remaining 3 put the two having total value greater then the third one into smaller partition
     //and the 3rd one to larger bucket 
     unused.remove(i);
     unused.remove(j);
     int middle = unused.first();
     
     if(diffSum > 0){
      if(A[i]+A[middle] > A[j]){
       partition2.add(A[i]);
       partition2.add(A[middle]);
       partition1.add(A[j]);
       part2Sum += A[i]+A[middle];
       part1Sum += A[j];
      }
      else{
       partition2.add(A[j]);
       partition1.add(A[i]);
       partition1.add(A[middle]);
       part1Sum += A[i]+A[middle];
       part2Sum += A[j];
      }
     }
     else{
      if(A[i]+A[middle] > A[j]){
       partition1.add(A[i]);
       partition1.add(A[middle]);
       partition2.add(A[j]);
       part1Sum += A[i]+A[middle];
       part2Sum += A[j];
      }
      else{
       partition1.add(A[j]);
       partition2.add(A[i]);
       partition2.add(A[middle]);
       part2Sum += A[i]+A[middle];
       part1Sum += A[j];
      }
     }
    break;
    default:
   }
   
   diffSum = part1Sum-part2Sum;
   break;
  }
  
  //first take the largest and the smallest element to create a pair to be inserted into a partition
  //we do this for having a balanced distribute of the numbers in the partitions
  //add pair (i, j) to the smaller partition 
  int pairSum = A[i]+A[j];
  int partition = diffSum > 0 ? 2 : 1;
  if(partition == 1){
   partition1.add(A[i]);
   partition1.add(A[j]);
   part1Sum += pairSum;
  }
  else{
   partition2.add(A[i]);
   partition2.add(A[j]);
   part2Sum += pairSum;
  }
  
  //update diff
  diffSum = part1Sum-part2Sum;
  //we have used pair (i, j)
  unused.remove(i);
  unused.remove(j);
  //move j to next big element to the left
  j = unused.last();
  //now find the buddy for j to be paired with such that sum of them is as close as to pairSum
  //so we will find such buddy A[k], i<=k<j such that value of ((A[j]+A[k])-pairSum) is minimized.
  int buddyIndex = unused.first();
  int minPairSumDiff = Integer.MAX_VALUE;
  for(int k = buddyIndex; k<j; k++){
   if(!unused.contains(k))
    continue;
   
   int compPairSum = A[j]+A[k];
   int pairSumDiff = Math.abs(pairSum-compPairSum);
   
   if(pairSumDiff < minPairSumDiff){
    minPairSumDiff = pairSumDiff;
    buddyIndex = k;
   }
  }
  
  //we now find buddy for j. So we add pair (j,buddyIndex) to the other partition
  if(j != buddyIndex){
   pairSum = A[j]+A[buddyIndex];
   if(partition == 2){
    partition1.add(A[j]);
    partition1.add(A[buddyIndex]);
    part1Sum += pairSum;
   }
   else{
    partition2.add(A[j]);
    partition2.add(A[buddyIndex]);
    part2Sum += pairSum;
   }
   
   //we have used pair (j, buddyIndex)
   unused.remove(j);
   unused.remove(buddyIndex);
  }
 }
 
 //if diffsum is greater than zero then we can further try to optimize by swapping 
 //a larger elements in large partition with an small element in smaller partition
 //O(n^2) operation with O(n) space
 if(diffSum != 0){
  Collections.sort(partition1);
  Collections.sort(partition2);
  
  diffSum = part1Sum-part2Sum;
  ArrayList<Integer> largerPartition = (diffSum > 0) ? partition1 : partition2;
  ArrayList<Integer> smallerPartition = (diffSum > 0) ? partition2 : partition1;
  
  int prevDiff = Math.abs(diffSum);
  int largePartitonSwapCandidate = -1;
  int smallPartitonSwapCandidate = -1;
  //find one of the largest element from large partition and smallest from the smaller partition to swap 
  //such that it overall sum difference in the partitions are minimized
  for(i = 0; i < smallerPartition.size(); i++){
   for(j = largerPartition.size()-1; j>=0; j--){
    int largerVal = largerPartition.get(j);
    int smallerVal = smallerPartition.get(i);
    
    //no point of swapping larger value from smaller partition
    if(largerVal <= smallerVal){
     continue;
    }

    //new difference if we had swapped these elements
    int diff = Math.abs(prevDiff - 2*Math.abs(largerVal - smallerVal));
    if(diff == 0){
     largerPartition.set(j, smallerVal);
     smallerPartition.set(i, largerVal);
     return new ArrayList[]{largerPartition, smallerPartition};
    }
    //find the pair to swap that minimizes the sum diff
    else if (diff < prevDiff){
     prevDiff = diff;
     largePartitonSwapCandidate = j;
     smallPartitonSwapCandidate = i;
    }
   }
  }
  
  //if we indeed found one such a pair then swap it. 
  if(largePartitonSwapCandidate >=0 && smallPartitonSwapCandidate >=0){
   int largerVal = largerPartition.get(largePartitonSwapCandidate);
   int smallerVal = smallerPartition.get(smallPartitonSwapCandidate);
   largerPartition.set(largePartitonSwapCandidate, smallerVal);
   smallerPartition.set(smallPartitonSwapCandidate, largerVal);
   return new ArrayList[]{largerPartition, smallerPartition};
  }
 }
 
 return new ArrayList[]{partition1, partition2};
}

Read full article from Equal partitioning with minimum difference in sum - Algorithms and Problem SolvingAlgorithms and Problem Solving

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts