0

The problem can be accessed from this link https://leetcode.com/problems/optimal-account-balancing/

*** Didn't realize this was only accessible by premium members, here is the problem statement and examples***

You are given an array of transactions transactions where transactions[i] = [fromi, toi, amounti] indicates that the person with ID = fromi gave amounti $ to the person with ID = toi.

Return the minimum number of transactions required to settle the debt.

Example 1:

Input: transactions = [[0,1,10],[2,0,5]]
Output: 2
Explanation:
Person #0 gave person #1 $10.
Person #2 gave person #0 $5.
Two transactions are needed. One way to settle the debt is person #1 pays person #0 and #2 $5 each.

Example 2:

Input: transactions = [[0,1,10],[1,0,1],[1,2,5],[2,0,5]]
Output: 1
Explanation:
Person #0 gave person #1 $10.
Person #1 gave person #0 $1.
Person #1 gave person #2 $5.
Person #2 gave person #0 $5.
Therefore, person #1 only need to give person #0 $4, and all debt is settled.

Constraints:

1 <= transactions.length <= 8
transactions[i].length == 3
0 <= fromi, toi < 12
fromi != toi
1 <= amounti <= 100

Questions

The first thing is, I am trying to understand how the dp function inside works. I don't use use bitwise operation too much but am vaguely familiar with what shifting, ^(Xor), and mask does but in this example, I'm having a hard time of putting them together.

Secondly, maybe I'll have a better idea once I understand the first problem. However if you could shed some light on what it's memoizing, the time complexity, and how that is more optimal, that would be awesome.

Thirdly, I have come up with my solution to this problem which is at the bottom of this post. I used plain backtracking but when it comes to analyzing the time complexity, I am slightly uncertain. My intuition is that since for loop inside the 'backtrack' function is going from 0 -> len(balance) then 1-> len(balance) ... so it'd be O(n^2)? (if we assume n = len(balance)). Correct me if I am wrong.

Truly thank you for your help in advance.

class Solution:
    def minTransfers(self, T: List[List[int]]) -> int:
        p = [0] * 12
        for f,t,a in T:
            p[f] -= a
            p[t] += a
        arr = []
        for a in p:
            if a != 0:
                arr.append(a)
        memo = {}
        def dp(count, cur, mask):
            nonlocal memo
            if (count, cur, mask) in memo:
                return memo[(count, cur, mask)]
            if mask == 0:
                return 0
            res = inf
            for i in range(len(arr)):
                if (1<<i)&mask:
                    if cur+arr[i]==0:
                        res = min(res, dp(0, 0, (1<<i)^mask)+count)
                    else:
                        res = min(res, dp(count+1, cur+arr[i], (1<<i)^mask))
            memo[(count, cur, mask)] = res
            return res
        mask = (1<<len(arr))-1
        return dp(0,0,mask)

My solution

class Solution:
    def minTransfers(self, transactions: List[List[int]]) -> int:
        # hash person giving and receiving money 

        map = {}

        for i in transactions:
            map[i[0]] = map.get(i[0],0)-i[2]
            map[i[1]] = map.get(i[1],0)+i[2]
        
        balance = [] 
        for key,val in map.items():
            if val != 0:
                balance.append(val)
        
        def backtrack(idx):
            if idx == len(balance):
                return 0 
            
            if balance[idx] == 0:
                return backtrack(idx+1)
            
            result = float('inf')

            for curr in range(idx+1,len(balance)):
                
                if balance[idx]*balance[curr] < 0:
                    balance[curr]+= balance[idx]
                    result = min(result,1+backtrack(idx+1))
                    balance[curr]-= balance[idx]
            return result 
        
        return backtrack(0)

  • 2
    *"first..., secondly..., thirdly..."*: A question on Stack Overflow should be limited to one question only, and should be focused. Also, *"Trying to understand"*, *"shed some light"*, *"I'm slightly uncertain"* ..etc are not very clear questions; in fact they are not questions to begin with. Choose one thing to ask about and make it very concrete what exactly need clarification. – trincot Dec 20 '22 at 23:25
  • Visiting the link, it says I must be a premium subscriber to view. Please explain the task the code is solving. (Links generally are unreliable since they can expire.) – גלעד ברקן Dec 21 '22 at 00:07
  • My bad, I updated the question @גלעד ברקן – Kang_the_Conqueror Dec 21 '22 at 02:04

1 Answers1

0

mask is keeping track of which accounts still need to be settled by setting a bit for those accounts.

if cur+arr[i]==0:
  res = min(res, dp(0, 0, (1<<i)^mask)+count)
...

is saying essentially "if the current amount settles the ith account, let's try settling it to see if res, which is keeping track of the least transactions needed, can be made smaller." (1<<i)^mask unsets the bit in the mask keeping track of whether the ith account has a balance.

The solution space, which is more-or-less the time and space complexity of the dp recursion, is O(count * curr * 2^num_accounts), where count is the maximum number of transactions and curr is the maximum amount tracked.

(I did not attempt to review the complexity of your solution.)

גלעד ברקן
  • 23,602
  • 3
  • 25
  • 61