517. Super Washing Machines


Problem Description

In this problem, you are given n super washing machines, each initially containing a certain number of dresses. The machines are aligned in a row, and you can make a move where you choose any m machines (where 1 <= m <= n) and pass one dress from each chosen machine to one of its adjacent machines simultaneously.

Your goal is to find the minimum number of moves required to redistribute the dresses so that all the machines have the same number of dresses. If it's not possible to reach this balance, the function should return -1.

To summarize:

  • You have an array machines representing the number of dresses in each washing machine.
  • You need to make all the washing machines have an equal number of dresses using the fewest moves possible.
  • A move consists of choosing a subgroup of machines and shifting a dress from each one to an adjacent machine.
  • You must determine the minimum moves required, or return -1 if equal distribution isn't possible.

Intuition

To solve this problem, one must understand that if there is an average number of dresses per machine that isn't a whole number, it's impossible to equally distribute the dresses since you can't split a dress. This is the first check made: if the total number of dresses is not divisible by the number of machines, the method will immediately return -1.

Assuming equal distribution is possible, our goal is to identify how far each machine is from the average and to calculate the number of steps needed to equalize the distribution.

The solution does this by:

  • Calculating the average number of dresses per machine (k).
  • Initializing two variables: s, which will maintain the cumulative difference from the average at each step, and ans, which will hold the maximum number of moves observed so far.

With each iteration over the machines, we:

  • Subtract the average k from the current number of dresses to find how many dresses need to be passed onto or received from adjacent machines (x -= k).
  • Add this difference to the cumulative sum s, which shows the total imbalance after the current machine.
  • Update ans with the maximum of its current value, the absolute current imbalance abs(s), and the current machine's specific imbalance x.

The absolute current imbalance abs(s) represents a sequence of redistributions among machines up to the current point.

Finally, ans is the accumulated aggregate of moves required, which gets returned as the minimum number of moves to make all washing machines have the same number of dresses.

Learn more about Greedy patterns.

Not Sure What to Study? Take the 2-min Quiz to Find Your Missing Piece:

What is the running time of the following code?

1int sqrt(int n) {
2  for (int guess = 1; guess * guess <= n; guess++) {
3    if (guess * guess == n) {
4      return guess;
5    }
6  }
7  return -1;
8}

Solution Approach

The solution uses a greedy algorithm to redistribute the dresses across the washing machines. The main principle behind the algorithm is that, at each step, the algorithm looks for the best local move that reduces the imbalance without caring for a global plan. To implement this, we use a single pass through the machines array, accumulating the necessary information to determine the minimum number of moves.

Here's a step-by-step breakdown of the solution approach:

  1. Calculate Total and Average: Determine the total number of dresses (sum(machines)) and the average (k), which is the target number for each machine to reach. Simultaneously, check if the total sum is divisible by the number of machines (n), which is necessary for an equal distribution. If not, we know immediately that the problem has no solution (return -1).

  2. Initialization: Initialize two variables: s is set to 0 and will be used to track the running imbalance as we iterate through the machines, and ans is also set to 0 and will keep a record of the maximum number of moves needed at any point.

  3. Iterate Through Machines: Iterate through each washing machine using x to represent the number of dresses in the current machine.

  4. Calculate the Local Imbalance: For each machine, calculate how many dresses it needs to give away or receive to reach the average by subtracting the average k from x (x -= k).

  5. Update the Cumulative Imbalance: Accumulate the current machine's imbalance to s (s += x). This gives us a cumulative sum at each point which represents the net dresses that need to be moved after considering the redistribution up to that machine.

  6. Determine Maximum Moves: After each adjustment, update ans to be the maximum of:

    • The previous maximum number of moves ans
    • The absolute value of the current cumulative imbalance abs(s), which indicates the minimum moves required for the current and all previous machines to achieve balance.
    • The current machine’s specific surplus or deficit x, which shows the minimum moves the current machine alone needs irrespective of the cumulative sum.
  7. Return: After processing all machines, you're left with the maximum value in ans that represents the minimum moves required to balance the dresses across all washing machines.

The algorithm uses a very straightforward data structure - a simple array to represent the machines and their respective counts of dresses. The pattern employed here is largely one of accumulation and tracking the maximum requirement, which is typical of problems where you must consider a running total and update an answer based on local constraints (in this case, the machine’s individual and cumulative imbalance).

This approach effectively balances the load across all machines in the minimum number of moves, taking into account that multiple redistributions might be happening simultaneously during each move.

Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:

Given an array of 1,000,000 integers that is almost sorted, except for 2 pairs of integers. Which algorithm is fastest for sorting the array?

Example Walkthrough

Let's assume we have an array of washing machines where [1, 0, 5] represents the number of dresses in the respective machines. Let's walk through the solution approach step-by-step.

  1. Calculate Total and Average:

    • The total sum of dresses is 1 + 0 + 5 = 6.
    • The number of machines, n, is 3.
    • Calculate the average dresses per machine, k, which is sum / n = 6 / 3 = 2.
    • The total number of dresses is evenly divisible by the number of machines, so a solution is possible.
  2. Initialization:

    • We set s = 0 and ans = 0.
  3. Iterate Through Machines:

    • We will iterate through each machine, starting from the first.
  4. Calculate the Local Imbalance and Update the Cumulative Imbalance:

    • For the first machine, x = 1. We need x to be equal to the average k = 2. Thus, x -= k gives us -1. The machine needs 1 dress.
    • Update s with x. Now, s = -1.
    • Determine maximum moves and update ans. Ans will be the max of ans, abs(s), and abs(x), so ans = max(0, 1, 1) = 1.
  5. Iterate to the Next Machine:

    • For the second machine, x = 0. To reach the average k, it needs 2 dresses. Thus, x -= k gives us -2.
    • Update s with x. Now, s += (-2) => s = -3.
    • Update ans. ans = max(1, abs(-3), abs(-2)) = 3.
  6. Iterate to the Third Machine:

    • For the third machine, x = 5. To reach the average k, it must give away 3 dresses. Thus, x -= k gives us 3.
    • Update s with x. Now, s += 3 => s = 0. All machines are now balanced.
    • Update ans. ans = max(3, abs(0), abs(3)) = 3.
  7. Return:

    • The iteration is complete and the maximum value in ans is 3.
    • The algorithm returns 3 as the minimum number of moves required to balance the dresses across all washing machines.

In summary, the example demonstrates how the algorithm checks for the possibility of equal distribution, iterates to calculate individual and cumulative imbalances and continuously updates the number of moves required based on the maximum imbalance observed at each step. The final answer of 3 moves accounts for the most demanding redistribution that occurs during the process.

Solution Implementation

1class Solution:
2    def findMinMoves(self, machines: List[int]) -> int:
3        # Calculate the length of the machines list.
4        machine_count = len(machines)
5
6        # Compute total dresses and the expected dresses per machine, along with a remainder.
7        total_dresses, remainder = divmod(sum(machines), machine_count)
8
9        # If there is a remainder, we can't equally distribute dresses to all machines.
10        if remainder:
11            return -1
12
13        # Initialize variables for the answer and the running balance.
14        max_moves = 0
15        balance = 0
16
17        # Iterate over each machine.
18        for dresses_in_machine in machines:
19            # Calculate the number of dresses to move for this machine to reach the expected count.
20            dresses_to_move = dresses_in_machine - total_dresses
21
22            # Increment the balance, which represents the ongoing "debt" or "surplus" from left to right.
23            balance += dresses_to_move
24
25            # The maximum number of moves required is the maximum of three values:
26            # 1. Current max_moves (the max encountered so far)
27            # 2. The absolute balance (as we may need to move dresses across multiple machines)
28            # 3. Dresses to move for the current machine (as it may require a lot of adding/removing)
29            max_moves = max(max_moves, abs(balance), dresses_to_move)
30
31        # Return the maximum number of moves needed to balance all machines.
32        return max_moves
33
1class Solution {
2    public int findMinMoves(int[] machines) {
3        int totalDresses = 0; // Sum of all dresses across the machines
4      
5        // Calculate the total number of dresses
6        for (int dresses : machines) {
7            totalDresses += dresses;
8        }
9      
10        // If total number of dresses is not divisible by the number of machines, there is no solution
11        if (totalDresses % machines.length != 0) {
12            return -1;
13        }
14      
15        // Calculate the average number of dresses per machine
16        int averageDresses = totalDresses / machines.length;
17      
18        // Initialize variables to track the current imbalance and the maximum number of moves required
19        int imbalance = 0;
20        int maxMoves = 0;
21      
22        // Iterate over each machine to calculate the required moves
23        for (int dresses : machines) {
24            // The number of dresses to be moved from the current machine to reach the average
25            dresses -= averageDresses;
26          
27            // Update the imbalance of dresses after considering the current machine's contribution
28            imbalance += dresses;
29          
30            // The maximum number of moves is the maximum of three quantities:
31            // 1. Current maximum number of moves
32            // 2. The absolute value of the current imbalance
33            // 3. The number of dresses to be moved from the current machine
34            maxMoves = Math.max(maxMoves, Math.max(Math.abs(imbalance), dresses));
35        }
36      
37        // Return the maximum number of moves required to balance the machines
38        return maxMoves;
39    }
40}
41
1#include <vector>
2#include <numeric>
3#include <algorithm>
4
5class Solution {
6public:
7    int findMinMoves(vector<int>& machines) {
8        int totalDresses = accumulate(machines.begin(), machines.end(), 0); // Sum of all dresses in machines
9        int numMachines = machines.size(); // Number of machines
10      
11        // If the total number of dresses is not divisible by the number of machines,
12        // it is impossible to balance the machines with an equal number of dresses.
13        if (totalDresses % numMachines != 0) {
14            return -1;
15        }
16      
17        // Calculate the average number of dresses per machine for balanced state
18        int averageDresses = totalDresses / numMachines;
19      
20        // Initialize cumulative imbalance and the answer (max number of moves required)
21        int cumulativeImbalance = 0;
22        int maxMoves = 0;
23      
24        // Iterate over each machine
25        for (int dressesInMachine : machines) {
26            // Calculate the imbalance for the current machine
27            int imbalance = dressesInMachine - averageDresses;
28          
29            // Update the cumulative imbalance
30            cumulativeImbalance += imbalance;
31          
32            // The minimum number of moves required is the maximum of three values:
33            // 1. The current maxMoves,
34            // 2. The absolute value of cumulative imbalance (for adjustments across machines),
35            // 3. The current imbalance (if a machine requires more moves on its own).
36            maxMoves = max({maxMoves, abs(cumulativeImbalance), imbalance});
37        }
38      
39        // Return the minimum number of moves required to balance all machines.
40        return maxMoves;
41    }
42};
43
1function findMinMoves(machines: number[]): number {
2    const totalMachines = machines.length;
3    let totalDresses = machines.reduce((accumulated, current) => accumulated + current, 0);
4
5    // If the total number of dresses cannot be evenly distributed, return -1.
6    if (totalDresses % totalMachines !== 0) {
7        return -1;
8    }
9
10    const dressesPerMachine = Math.floor(totalDresses / totalMachines);
11    let imbalance = 0;  // Used to track the imbalance of dresses during distribution.
12    let minMoves = 0;   // The minimum number of moves required to balance.
13
14    // Iterate through each machine.
15    for (let dressesInMachine of machines) {
16        // Calculate the number of excess dresses in current machine.
17        dressesInMachine -= dressesPerMachine;
18        // Update the imbalance by adding the excess dresses from the current machine.
19        imbalance += dressesInMachine;
20      
21        // The minimum moves is the maximum of the current minMoves,
22        // the absolute imbalance, and the excess dresses in the current machine.
23        minMoves = Math.max(minMoves, Math.abs(imbalance), dressesInMachine);
24    }
25
26    // Return the minimum number of moves required to balance the machines.
27    return minMoves;
28}
29
Not Sure What to Study? Take the 2-min Quiz:

Which algorithm should you use to find a node that is close to the root of the tree?

Time and Space Complexity

The provided code examines an array of machines representing the number of dresses in each laundry machine and calculates the minimum number of moves required to equalize the number of dresses in all machines. Here's the computational complexity analysis:

  • Time Complexity:

    The function findMinMoves involves a single for loop that iterates over the list of machines exactly once. Within this loop, only constant-time operations are performed: subtraction, addition, comparison, and assignment. Therefore, the time complexity is directly proportional to the length of the machines list, which is n.

    The final time complexity is O(n).

  • Space Complexity:

    The space complexity is calculated based on the additional space used by the algorithm aside from the input itself. Here, only a few integer variables are used (n, k, mod, ans, and s). There are no data structures that grow with the size of the input.

    Therefore, the space complexity is O(1) for the constant extra space used.

Learn more about how to find time and space complexity quickly using problem constraints.

Fast Track Your Learning with Our Quick Skills Quiz:

Consider the classic dynamic programming of fibonacci numbers, what is the recurrence relation?


Recommended Readings


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫