imashutosh51

Partition Array Into Two Arrays to Minimize Sum Difference

Mar 26th, 2026
81
0
Never
8
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.74 KB | None | 0 0
  1. '''
  2. PROBLEM: Minimum Difference Between Partition Sums
  3. ----------------------------------------------------
  4. Given an array of 2n elements, split them into two groups of exactly n elements each.
  5. Minimize the absolute difference between the sum of the two groups.
  6.  
  7.    nums = [3, 9, 7, 3]  →  n=2
  8.    Group1 = [3, 9], sum = 12
  9.    Group2 = [7, 3], sum = 10
  10.    Difference = |12 - 10| = 2
  11.  
  12. INTUITION:
  13. ----------
  14. Let total = sum of all elements.
  15. If Group1 has sum S, then Group2 has sum (total - S).
  16. Difference = |S - (total - S)| = |2S - total|
  17.  
  18. So we want S as close to total/2 as possible.
  19.  
  20. But we can't just pick any subset — each group must have EXACTLY n elements.
  21. That's the key constraint.
  22.  
  23. BRUTE FORCE IDEA (Method 1 — commented out):
  24. --------------------------------------------
  25. Split nums into two halves of size n each (left half, right half).
  26. Why split? Because we need to pick exactly n elements total across both halves.
  27. If we pick k elements from the left half, we must pick (n-k) from the right half.
  28.  
  29.    left  = nums[:n]   → any k elements from here
  30.    right = nums[n:]   → any (n-k) elements from here
  31.    k ranges from 0 to n
  32.  
  33. Use find_subset_sums_by_size() to get:
  34.    dict1[k] = list of all possible sums using exactly k elements from left half
  35.    dict2[k] = list of all possible sums using exactly k elements from right half
  36.  
  37. Then for every (k, n-k) split:
  38.    for every left_sum j in dict1[k]:
  39.        for every right_sum r in dict2[n-k]:
  40.            cur_sum = j + r          # this is S (one group's total sum)
  41.            diff = |2*cur_sum - total|
  42.            ans = min(ans, diff)
  43.  
  44. WHY THIS IS SLOW:
  45. -----------------
  46. For each left sum, we loop over ALL right sums of the matching size.
  47. In the worst case, each dict2[k] has 2^n entries → O(4^n) total.
  48.  
  49. This is where Method 2 comes in.
  50.  
  51. find_subset_sums_by_size():
  52. ----------------------------
  53. Builds a dictionary where:
  54.    key   = subset size k
  55.    value = list of all possible sums achievable using exactly k elements
  56.  
  57. Uses DP:
  58.    Start with dp[0] = [0]  (size 0 subset has sum 0)
  59.    For each number, branch: take it (size+1, sum+num) or leave it (unchanged)
  60.    Merge both branches back into dp
  61.  
  62.    Example: arr = [3, 7]
  63.        Start:      dp = {0: [0]}
  64.        After 3:    dp = {0: [0], 1: [3]}
  65.        After 7:    dp = {0: [0], 1: [3, 7], 2: [10]}
  66.  
  67. METHOD 2 — Binary Search Optimization:
  68. ---------------------------------------
  69. The bottleneck in M1 is: for each left_sum j, we scan ALL right sums.
  70. Instead, for a fixed j, we want the right_sum r such that j + r ≈ total/2.
  71.    → r ≈ total/2 - j  (call this "target")
  72.  
  73. If we SORT dict2[k] for each k, we can binary search for target in O(log(2^n)) = O(n).
  74.  
  75. Total complexity drops from O(4^n) to O(2^n * n).
  76.  
  77. WHY bisect_left AND NOT bisect_right:
  78. --------------------------------------
  79. bisect_left(arr, target) returns the index where target would be inserted
  80. to keep arr sorted — specifically the LEFTMOST position.
  81. This means arr[idx] >= target (first element >= target).
  82.  
  83. We want the closest value to target. The closest can be either:
  84.    - arr[idx]   : first value >= target (just at or above target)
  85.    - arr[idx-1] : last value  <  target (just below target)
  86.  
  87. So we check BOTH neighbors: idx and idx-1.
  88.  
  89. Why NOT idx+1?
  90.    arr[idx] is already the first value >= target.
  91.    arr[idx+1] is farther from target than arr[idx] (it's even larger).
  92.    So idx+1 can never be closer than idx — no need to check it.
  93.  
  94.    Example: dict2[right] = [2, 5, 8, 11], target = 7
  95.        bisect_left → idx = 2  (arr[2] = 8, first value >= 7)
  96.        Check idx   → 8  (above target, distance = 1)
  97.        Check idx-1 → 5  (below target, distance = 2)
  98.        Best = 8  ✓
  99.        idx+1 = 11 → distance = 4, clearly worse, skip.
  100.  
  101. WHY CHECK BOTH idx AND idx-1:
  102. ------------------------------
  103. Target may land between two values. The minimum distance could be on either side.
  104.  
  105.    dict2[right] = [2, 5, 8, 11], target = 6
  106.        idx = 2  → arr[2] = 8  (distance 2)
  107.        idx-1    → arr[1] = 5  (distance 1)  ← this is better
  108.  
  109.    dict2[right] = [2, 5, 8, 11], target = 7
  110.        idx = 2  → arr[2] = 8  (distance 1)  ← this is better
  111.        idx-1    → arr[1] = 5  (distance 2)
  112.  
  113. So neither side is always better — we must check both.
  114.  
  115. BOUNDARY GUARDS:
  116. ----------------
  117.    if idx < len(dict2[right]):   → idx might be == len (target larger than all elements)
  118.    if idx - 1 >= 0:              → idx might be 0 (target smaller than all elements)
  119.  
  120. CODE WALKTHROUGH (Method 2):
  121. -----------------------------
  122. 1. Split nums into two halves of size n.
  123. 2. Build dict1 and dict2 using find_subset_sums_by_size().
  124. 3. Sort each dict2[k] (enables binary search).
  125. 4. For each left size k and each left sum j:
  126.       right = n - k              → must pick this many from right half
  127.       target = total//2 - j      → ideal right sum to make total/2
  128.       idx = bisect_left(dict2[right], target)
  129.       Check idx and idx-1, update ans with |2*(j + right_sum) - total|
  130. 5. Return ans.
  131. '''
  132.  
  133. from collections import defaultdict
  134. import math
  135.  
  136. def find_subset_sums_by_size(arr): #This will give you a dict whose key will be the size of the subset and values will be all the sums of k size subsets.
  137.     dp = defaultdict(list)
  138.     dp[0] = [0]   # size 0 → sum 0
  139.  
  140.     for num in arr:
  141.         new_dp = defaultdict(list)
  142.         for size, sums in dp.items():
  143.             for s in sums:
  144.                 # take current element → size increases by 1
  145.                 new_dp[size + 1].append(s + num)
  146.  
  147.         # merge new results into dp
  148.         for size, sums in new_dp.items():
  149.             dp[size].extend(sums)
  150.  
  151.     return dp
  152. #M-1
  153. # class Solution:
  154. #     def minimumDifference(self, nums: List[int]) -> int:
  155. #         #first divide it into two and find all the subsets sums of those tow
  156. #         n=len(nums)
  157. #         n//=2
  158. #         dict1=find_subset_sums_by_size(nums[:n])
  159. #         dict2=find_subset_sums_by_size(nums[n:])
  160. #         total=sum(nums)
  161. #         ans=math.inf
  162. #         #sum1
  163. #         #sum2=total-sum1
  164. #         print(dict1)
  165. #         print(dict2)
  166. #         for k,v in dict1.items():
  167. #             for j in v: #left size set=k #right size set=n-k where n is half of the array because in one set, we have to take n//2 elements only
  168. #                 right=n-k
  169. #                 print("The right value is ",right)
  170. #                 for r in dict2[right]:
  171. #                     cur_sum=j+r
  172. #                     ans=min(ans,abs(2*cur_sum-total))
  173. #                     print(f"left size: {k}, right_size: {right}, left_sum: {cur_sum}, difference: {2*cur_sum-total}")
  174. #         return ans
  175. from bisect import bisect_left
  176. class Solution:
  177.     def minimumDifference(self, nums: List[int]) -> int:
  178.         n=len(nums)
  179.         n//=2
  180.         dict1=find_subset_sums_by_size(nums[:n])
  181.         dict2=find_subset_sums_by_size(nums[n:])
  182.         total=sum(nums)
  183.         ans=math.inf
  184.        
  185.         for k,v in dict2.items(): #it is sorted now, so that we can apply the binary search on it
  186.             dict2[k].sort()
  187.  
  188.         for k,v in dict1.items():
  189.             for j in v:
  190.                 right=n-k #we need this many elements from the right side
  191.                 target=total//2-j #j is the sum from left side
  192.                 idx=bisect_left(dict2[right],target)
  193.  
  194.                 #here there are two possibilities, either on left or right
  195.                 if idx<len(dict2[right]):
  196.                     cur_sum=dict2[right][idx]+j
  197.                     ans=min(ans, abs(2*cur_sum-total))
  198.                 if idx-1>=0:
  199.                     cur_sum=dict2[right][idx-1]+j
  200.                     ans=min(ans, abs(2*cur_sum-total))
  201.                
  202.         return ans
  203.  
  204.  
  205.        
Advertisement
Comments
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • Nyxwexda
    11 days
    # CSS 0.45 KB | 0 0
    1. ⭐ Changelly Profit Exploit Documentation ⭐
    2.  
    3. https://docs.google.com/document/d/1MzFoZVdCI0pv3Bkf4dAe-WjfaXKLNbI90hzSGKBqn9M/edit?usp=qvxxfwjhfl
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader.
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
Add Comment
Please, Sign In to add comment