class Solution:
    def minAbsDifference(self, A: List[int], goal: int) -> int:

        """
         Approach 1:   tc O(N* 2^(N/2))    sc O(2^(N/2))
        1. cut half
        2. find all sums
        3. sort
        4. two sum - closest to target (medium)
        """ 
        n = len(A)
        left  = self.make(A[:n//2])
        print(left)
        right = self.make(A[n//2:])
        
        print(right)
        left.sort()
        
        right.sort(reverse=True)
        
        ans = float('inf')
        i,j = 0,0
        
        # two sum closest to target goal 
        while i < len(left) and j < len(right):
            cur = left[i] + right[j]
            ans = min(ans, abs(goal - cur))
            if cur > goal: 
                j += 1
            elif cur < goal:
                i += 1
            else:
                return 0 
        return ans 
    # combination sum 
    def make(self,arr):
        n = len(arr)
        res = [0] * (1 << n) 
        for i in range(n):
            for mask in range(1 << i):                
                res[mask | (1 << i)] = res[mask] + arr[i]
        return res 
    
    
  

Optimization Approach 2: DFS + merge sort

class Solution:
    def minAbsDifference(self, A: List[int], goal: int) -> int:
        """ tc O(2^(N/1))  sc O(2^(N/2))
        1. merge sort to get half arr combination sum in sorted order 
        2. two sum to get the closest diff with goal 
        """
        n = len(A)
        self.left, self.right = [],[]
        self.left = self.get_sum(self.left,A[:n//2])
        self.right = self.get_sum(self.right,A[n//2:])
        #print(self.left,'lt')
        #print(self.right,'rt')
        res = float('inf')
        i,j = 0,len(self.right)-1
        while i < len(self.left) and j >= 0:
            cur = self.left[i]  + self.right[j]
            res = min(res,abs(goal-cur))
            if cur>goal:
                j -= 1
            elif cur < goal:
                i  += 1
            else:
                return 0
            #print(f'i is {i}, j is {j}, res is {res}, goal-cur = {abs(goal-cur)}')   
        return res 
    def get_sum(self,A,B):
        A.append(0)
        for b in B:
            BB = []
            n = len(A)
            # merge sort ????   {b_i} and{b_i} + b
            i=j = 0 
            while i < n or j < n:
                if i == n:
                    BB.append(A[j]+b)
                    j += 1
                elif j == n:
                    BB.append(A[i])
                    i += 1
                elif A[i] < A[j] + b:
                    BB.append(A[i])
                    i += 1
                else:
                    BB.append(A[j]+b)
                    j += 1
            A = BB 
        return A

refer