Given an integer array arr[] representing houses built along a straight line, each value arr[i] represents a certain number of wine bottles that a wants to buy or sell.
- If arr[i] < 0, then the i-th house wants to sell |arr[i]| bottles of wine.
- If arr[i] > 0, then the i-th house wants to buy arr[i] bottles of wine.
Find the minimum total work required so that all houses can fulfill their wine buy/sell requirements.
- Transporting one bottle of wine from one house to an adjacent house costs 1 unit of work.
- It is guaranteed that the sum of all elements of the array is 0.
Examples:
Input: arr[] = [5, -4, 1, -3, 1]
Output: 9
Explanation:Â
House 1 sells 4 bottles to house 0, so work done is 4 × 1 = 4.
Updated array becomes: [1, 0, 1, -3, 1]
Now, house 3 sells:
1 bottle to house 0 -> work = 3
1 bottle to house 2 -> work = 1
1 bottle to house 4 -> work = 1
Total additional work = 3 + 1 + 1 = 5
Hence, total minimum work = 4 + 5 = 9.
So the answer for this test case is 9.
Input: arr[] = [-1000, -1000, -1000, 1000, 1000, 1000]
Output: 9000
Explanation:Â
House 0 sells 1000 bottles to house 3 -> work = 1000 × 3 = 3000
House 1 sells 1000 bottles to house 4 -> work = 1000 × 3 = 3000
House 2 sells 1000 bottles to house 5 -> work = 1000 × 3 = 3000
Total minimum work = 3000 + 3000 + 3000 = 9000.
So the answer for this test case is 9000.
Table of Content
[Naive Approach] Simulate Every Wine Transfer - O(n ^ 2) Time and O(1) Space
The idea is to process each seller and search for buyers one by one, transferring as many bottles as possible until all wine requirements are fulfilled.
#include <iostream>
#include <vector>
using namespace std;
int wineSelling(vector<int> &arr)
{
int n = arr.size();
int res = 0;
// Process each seller
for (int i = 0; i < n; i++)
{
// Skip non-sellers
if (arr[i] >= 0)
continue;
int need = -arr[i];
// Search for buyers
for (int j = 0; j < n && need > 0; j++)
{
// Skip non-buyers
if (arr[j] <= 0)
continue;
// Transfer the maximum possible bottles
int x = min(need, arr[j]);
// Add the work required for this transfer
res += x * abs(i - j);
need -= x;
arr[j] -= x;
}
}
return res;
}
int main()
{
vector<int> arr = {-1000, -1000, -1000, 1000, 1000, 1000};
cout << wineSelling(arr);
return 0;
}
import java.util.Arrays;
public class GFG {
public static int wineSelling(int[] arr)
{
int n = arr.length;
int res = 0;
// Process each seller
for (int i = 0; i < n; i++) {
// Skip non-sellers
if (arr[i] >= 0)
continue;
int need = -arr[i];
// Search for buyers
for (int j = 0; j < n && need > 0; j++) {
// Skip non-buyers
if (arr[j] <= 0)
continue;
// Transfer the maximum possible bottles
int x = Math.min(need, arr[j]);
// Add the work required for this transfer
res += x * Math.abs(i - j);
need -= x;
arr[j] -= x;
}
}
return res;
}
public static void main(String[] args)
{
int[] arr
= { -1000, -1000, -1000, 1000, 1000, 1000 };
System.out.println(wineSelling(arr));
}
}
def wineSelling(arr):
n = len(arr)
res = 0
# Process each seller
for i in range(n):
# Skip non-sellers
if arr[i] >= 0:
continue
need = -arr[i]
# Search for buyers
for j in range(n):
if need <= 0:
break
# Skip non-buyers
if arr[j] <= 0:
continue
# Transfer the maximum possible bottles
x = min(need, arr[j])
# Add the work required for this transfer
res += x * abs(i - j)
need -= x
arr[j] -= x
return res
if __name__ == "__main__":
arr = [-1000, -1000, -1000, 1000, 1000, 1000]
print(wineSelling(arr))
using System;
using System.Collections.Generic;
public class GFG {
public static int wineSelling(List<int> arr)
{
int n = arr.Count;
int res = 0;
// Process each seller
for (int i = 0; i < n; i++) {
// Skip non-sellers
if (arr[i] >= 0)
continue;
int need = -arr[i];
// Search for buyers
for (int j = 0; j < n && need > 0; j++) {
// Skip non-buyers
if (arr[j] <= 0)
continue;
// Transfer the maximum possible bottles
int x = Math.Min(need, arr[j]);
// Add the work required for this transfer
res += x * Math.Abs(i - j);
need -= x;
arr[j] -= x;
}
}
return res;
}
public static void Main()
{
List<int> arr = new List<int>{ -1000, -1000, -1000,
1000, 1000, 1000 };
Console.WriteLine(wineSelling(arr));
}
}
function wineSelling(arr)
{
let n = arr.length;
let res = 0;
// Process each seller
for (let i = 0; i < n; i++) {
// Skip non-sellers
if (arr[i] >= 0)
continue;
let need = -arr[i];
// Search for buyers
for (let j = 0; j < n && need > 0; j++) {
// Skip non-buyers
if (arr[j] <= 0)
continue;
// Transfer the maximum possible bottles
let x = Math.min(need, arr[j]);
// Add the work required for this transfer
res += x * Math.abs(i - j);
need -= x;
arr[j] -= x;
}
}
return res;
}
let arr = [ -1000, -1000, -1000, 1000, 1000, 1000 ];
console.log(wineSelling(arr));
Output
9000
[Expected Approach - 1] Simulating Wine Transfers Using Two Pointers - O(n) Time and O(n) Space
The idea is to store all buyers and sellers separately and use two pointers to match them. Transfer the maximum possible bottles at each step and add the corresponding work.
Let us understand with an example:
Input: arr[] = [-1000, -1000, -1000, 1000, 1000, 1000]
- Store all buyers and sellers along with their indices: buy = {(1000, 3), (1000, 4), (1000, 5)} and sell = {(1000, 0), (1000, 1), (1000, 2)}. Initialize i = 0, j = 0, and res = 0.
- Match seller (1000, 0) with buyer (1000, 3). Transfer 1000 bottles, so work = 1000 × (3 - 0) = 3000. Update res = 3000 and move both pointers.
- Match seller (1000, 1) with buyer (1000, 4). Transfer 1000 bottles, so work = 1000 × (4 - 1) = 3000. Update res = 6000 and move both pointers.
- Match seller (1000, 2) with buyer (1000, 5). Transfer 1000 bottles, so work = 1000 × (5 - 2) = 3000. Update res = 9000 and move both pointers.
- Both buyer and seller lists are exhausted, so the algorithm terminates and returns 9000.
#include <iostream>
#include <vector>
using namespace std;
int wineSelling(vector<int> &arr)
{
int n = arr.size();
vector<pair<int, int>> buy;
vector<pair<int, int>> sell;
// Store buyers and sellers
for (int i = 0; i < n; i++)
{
if (arr[i] > 0)
buy.push_back({arr[i], i});
else if (arr[i] < 0)
sell.push_back({-arr[i], i});
}
int i = 0, j = 0;
int res = 0;
// Match buyers and sellers
while (i < buy.size() && j < sell.size())
{
// Transfer the maximum possible bottles
int x = min(buy[i].first, sell[j].first);
// Add the work required for this transfer
res += x * abs(buy[i].second - sell[j].second);
buy[i].first -= x;
sell[j].first -= x;
// Move to the next buyer if satisfied
if (buy[i].first == 0)
i++;
// Move to the next seller if satisfied
if (sell[j].first == 0)
j++;
}
return res;
}
int main()
{
vector<int> arr = {-1000, -1000, -1000, 1000, 1000, 1000};
cout << wineSelling(arr);
return 0;
}
import java.util.ArrayList;
import java.util.List;
public class GFG {
public static int wineSelling(int[] arr)
{
int n = arr.length;
List<int[]> buy = new ArrayList<>();
List<int[]> sell = new ArrayList<>();
// Store buyers and sellers
for (int i = 0; i < n; i++) {
if (arr[i] > 0)
buy.add(new int[] { arr[i], i });
else if (arr[i] < 0)
sell.add(new int[] { -arr[i], i });
}
int i = 0, j = 0;
int res = 0;
// Match buyers and sellers
while (i < buy.size() && j < sell.size()) {
// Transfer the maximum possible bottles
int x = Math.min(buy.get(i)[0], sell.get(j)[0]);
// Add the work required for this transfer
res += x
* Math.abs(buy.get(i)[1]
- sell.get(j)[1]);
buy.get(i)[0] -= x;
sell.get(j)[0] -= x;
// Move to the next buyer if satisfied
if (buy.get(i)[0] == 0)
i++;
// Move to the next seller if satisfied
if (sell.get(j)[0] == 0)
j++;
}
return res;
}
public static void main(String[] args)
{
int[] arr
= { -1000, -1000, -1000, 1000, 1000, 1000 };
System.out.println(wineSelling(arr));
}
}
def wineSelling(arr):
n = len(arr)
buy = []
sell = []
# Store buyers and sellers
for i in range(n):
if arr[i] > 0:
buy.append([arr[i], i])
elif arr[i] < 0:
sell.append([-arr[i], i])
i = 0
j = 0
res = 0
# Match buyers and sellers
while i < len(buy) and j < len(sell):
# Transfer the maximum possible bottles
x = min(buy[i][0], sell[j][0])
# Add the work required for this transfer
res += x * abs(buy[i][1] - sell[j][1])
buy[i][0] -= x
sell[j][0] -= x
# Move to the next buyer if satisfied
if buy[i][0] == 0:
i += 1
# Move to the next seller if satisfied
if sell[j][0] == 0:
j += 1
return res
if __name__ == '__main__':
arr = [-1000, -1000, -1000, 1000, 1000, 1000]
print(wineSelling(arr))
using System;
using System.Collections.Generic;
public class GFG {
public static int wineSelling(List<int> arr)
{
int n = arr.Count;
List<Tuple<int, int> > buy
= new List<Tuple<int, int> >();
List<Tuple<int, int> > sell
= new List<Tuple<int, int> >();
// Store buyers and sellers
for (int i = 0; i < n; i++) {
if (arr[i] > 0)
buy.Add(new Tuple<int, int>(arr[i], i));
else if (arr[i] < 0)
sell.Add(new Tuple<int, int>(-arr[i], i));
}
int left = 0, right = 0;
int res = 0;
// Match buyers and sellers
while (left < buy.Count && right < sell.Count) {
// Transfer the maximum possible bottles
int x = Math.Min(buy[left].Item1,
sell[right].Item1);
// Add the work required for this transfer
res += x
* Math.Abs(buy[left].Item2
- sell[right].Item2);
buy[left] = new Tuple<int, int>(
buy[left].Item1 - x, buy[left].Item2);
sell[right] = new Tuple<int, int>(
sell[right].Item1 - x, sell[right].Item2);
// Move to the next buyer if satisfied
if (buy[left].Item1 == 0)
left++;
// Move to the next seller if satisfied
if (sell[right].Item1 == 0)
right++;
}
return res;
}
public static void Main()
{
List<int> arr = new List<int>{ -1000, -1000, -1000,
1000, 1000, 1000 };
Console.WriteLine(wineSelling(arr));
}
}
function wineSelling(arr)
{
let n = arr.length;
let buy = [];
let sell = [];
// Store buyers and sellers
for (let i = 0; i < n; i++) {
if (arr[i] > 0)
buy.push([ arr[i], i ]);
else if (arr[i] < 0)
sell.push([ -arr[i], i ]);
}
let i = 0, j = 0;
let res = 0;
// Match buyers and sellers
while (i < buy.length && j < sell.length) {
// Transfer the maximum possible bottles
let x = Math.min(buy[i][0], sell[j][0]);
// Add the work required for this transfer
res += x * Math.abs(buy[i][1] - sell[j][1]);
buy[i][0] -= x;
sell[j][0] -= x;
// Move to the next buyer if satisfied
if (buy[i][0] == 0)
i++;
// Move to the next seller if satisfied
if (sell[j][0] == 0)
j++;
}
return res;
}
let arr = [ -1000, -1000, -1000, 1000, 1000, 1000 ];
console.log(wineSelling(arr));
Output
9000
[Expected Approach - 2] Prefix Balance - O(n) Time and O(1) Space
The idea is to maintain the cumulative wine balance while traversing the houses. The absolute value of the balance at each position contributes to the minimum work.
Let us understand with an example:
Input: arr[] = [-1000, -1000, -1000, 1000, 1000, 1000]
- Initialize balance = 0 and res = 0.
- Process -1000: balance = -1000, so res += |-1000| = 1000. Process the next -1000: balance = -2000, res = 3000. Process the next -1000: balance = -3000, res = 6000.
- Process 1000: balance = -2000, so res = 8000. Process the next 1000: balance = -1000, res = 9000.
- Process the last 1000: balance = 0, so res += |0| = 0. Thus, res remains 9000.
- After traversing all houses, the algorithm returns 9000, which is the minimum total work required.
#include <iostream>
#include <vector>
using namespace std;
int wineSelling(vector<int> &arr)
{
int balance = 0;
int res = 0;
// Traverse all houses
for (int x : arr)
{
balance += x;
// Add work contributed by the current balance
res += abs(balance);
}
return res;
}
int main()
{
vector<int> arr = {-1000, -1000, -1000, 1000, 1000, 1000};
cout << wineSelling(arr);
return 0;
}
import java.util.ArrayList;
public class GFG {
public static int wineSelling(ArrayList<Integer> arr)
{
int balance = 0;
int res = 0;
// Traverse all houses
for (int x : arr) {
balance += x;
// Add work contributed by the current balance
res += Math.abs(balance);
}
return res;
}
public static void main(String[] args)
{
ArrayList<Integer> arr = new ArrayList<>();
arr.add(-1000);
arr.add(-1000);
arr.add(-1000);
arr.add(1000);
arr.add(1000);
arr.add(1000);
System.out.println(wineSelling(arr));
}
}
def wineSelling(arr):
balance = 0
res = 0
# Traverse all houses
for x in arr:
balance += x
# Add work contributed by the current balance
res += abs(balance)
return res
if __name__ == '__main__':
arr = [-1000, -1000, -1000, 1000, 1000, 1000]
print(wineSelling(arr))
using System;
using System.Collections.Generic;
public class GFG {
public static int wineSelling(List<int> arr)
{
int balance = 0;
int res = 0;
// Traverse all houses
foreach(int x in arr)
{
balance += x;
// Add work contributed by the current balance
res += Math.Abs(balance);
}
return res;
}
public static void Main()
{
List<int> arr = new List<int>{ -1000, -1000, -1000,
1000, 1000, 1000 };
Console.WriteLine(wineSelling(arr));
}
}
function wineSelling(arr)
{
let balance = 0;
let res = 0;
// Traverse all houses
for (let x of arr) {
balance += x;
// Add work contributed by the current balance
res += Math.abs(balance);
}
return res;
}
const arr = [ -1000, -1000, -1000, 1000, 1000, 1000 ];
console.log(wineSelling(arr));
Output
9000