17. Coin Piles

โœ… GFG solution to the Coin Piles problem: minimize coins removed to maintain difference โ‰ค k between any two piles using sliding window technique. ๐Ÿš€

The problem can be found at the following link: ๐Ÿ”— Question Link

๐Ÿงฉ Problem Description

You are given an array arr[] of integers, where each element represents the number of coins in a pile. You are also given an integer k. Your task is to remove the minimum number of coins such that the absolute difference between the number of coins in any two updated piles is at most k.

Note: You can also remove a pile by removing all the coins of that pile.

๐Ÿ“˜ Examples

Example 1

Input: arr[] = [2, 2, 2, 2], k = 0
Output: 0
Explanation: For any two piles the difference in the number of coins is <= 0.
So no need to remove any coin.

Example 2

Input: arr[] = [1, 5, 1, 2, 5, 1], k = 3
Output: 2
Explanation: If we remove one coin each from both the piles containing 5 coins,
then for any two piles the absolute difference in the number of coins is <= 3.

๐Ÿ”’ Constraints

  • $1 \le \text{arr.size()} \le 10^5$

  • $1 \le \text{arr}[i] \le 10^4$

  • $0 \le k \le 10^4$

โœ… My Approach

The optimal approach uses Sorting combined with Sliding Window technique to find the minimum coins to remove:

Sliding Window with Range Optimization

  1. Sort the Array:

    • Sort the array to group similar pile sizes together.

    • This allows us to consider contiguous ranges where max - min โ‰ค k.

  2. Calculate Total Sum:

    • Store the total sum of all coins for reference.

    • This helps in calculating removal costs efficiently.

  3. Sliding Window Technique:

    • For each possible starting position s, find the maximum range [s, e) where arr[e-1] - arr[s] โ‰ค k.

    • All piles in this range can coexist without violating the constraint.

  4. Optimization Strategy:

    • Keep piles in range: Sum of coins in window [s, e).

    • Remove prefix: All coins before position s.

    • Adjust suffix: Reduce piles after position e to arr[s] + k (or remove if too small).

  5. Cost Calculation:

    • Prefix removal cost: Sum of arr[0] to arr[s-1]

    • Window preservation: Keep all coins in [s, e)

    • Suffix adjustment: max(0, remaining_sum - (n-e) * (arr[s] + k))

๐Ÿ“ Time and Auxiliary Space Complexity

  • Expected Time Complexity: O(n log n), where n is the array size. Sorting takes O(n log n) and the sliding window traversal takes O(n) with each element visited at most twice.

  • Expected Auxiliary Space Complexity: O(1), as we only use constant extra space for variables (excluding the input array sorting space).

๐Ÿง‘โ€๐Ÿ’ป Code (C++)

class Solution {
public:
    int minimumCoins(vector<int>& a, int k) {
        sort(a.begin(), a.end());
        int n = a.size(), t = accumulate(a.begin(), a.end(), 0), res = t, w = 0, p = 0, e = 0;
        for (int s = 0; s < n; s++) {
            while (e < n && a[e] - a[s] <= k) w += a[e++];
            int r = max(0, (t - p - w) - (n - e) * (a[s] + k));
            res = min(res, p + r);
            if (e == s) e++; else w -= a[s];
            p += a[s];
        }
        return res;
    }
};
โšก View Alternative Approaches with Code and Analysis

๐Ÿ“Š 2๏ธโƒฃ Two Pointer with Prefix Sum

๐Ÿ’ก Algorithm Steps:

  1. Sort array and calculate total sum.

  2. Use two pointers to maintain valid window.

  3. Track prefix sum and window sum separately.

class Solution {
public:
    int minimumCoins(vector<int>& a, int k) {
        sort(a.begin(), a.end());
        int n = a.size(), t = accumulate(a.begin(), a.end(), 0), res = t, l = 0, r = 0, w = 0, p = 0;
        while (l < n) {
            while (r < n && a[r] - a[l] <= k) w += a[r++];
            res = min(res, p + max(0, (t - p - w) - (n - r) * (a[l] + k)));
            w -= a[l], p += a[l++];
            if (r <= l && r < n) w += a[r++];
        }
        return res;
    }
};

๐Ÿ“ Complexity Analysis:

  • Time: โฑ๏ธ O(n log n)

  • Auxiliary Space: ๐Ÿ’พ O(1)

โœ… Why This Approach?

  • Clear separation of concerns.

  • Easier to debug and maintain.

๐Ÿ“Š 3๏ธโƒฃ Sliding Window with Deque

๐Ÿ’ก Algorithm Steps:

  1. Use deque to maintain window elements.

  2. Efficiently add/remove elements from both ends.

  3. Track sum using deque operations.

class Solution {
public:
    int minimumCoins(vector<int>& a, int k) {
        sort(a.begin(), a.end());
        int n = a.size(), t = accumulate(a.begin(), a.end(), 0), res = t, p = 0, w = 0;
        deque<int> d;
        for (int i = 0, j = 0; i < n; i++) {
            while (j < n && a[j] - a[i] <= k) d.push_back(a[j]), w += a[j++];
            res = min(res, p + max(0, (t - p - w) - (n - j) * (a[i] + k)));
            if (!d.empty()) w -= d.front(), d.pop_front();
            p += a[i];
        }
        return res;
    }
};

๐Ÿ“ Complexity Analysis:

  • Time: โฑ๏ธ O(n log n)

  • Auxiliary Space: ๐Ÿ’พ O(n)

โœ… Why This Approach?

  • Explicit window management.

  • Good for understanding the algorithm.

๐Ÿ“Š 4๏ธโƒฃ Mathematical Optimization

๐Ÿ’ก Algorithm Steps:

  1. Pre-calculate cumulative sums.

  2. Use mathematical formulas to avoid repeated calculations.

  3. Optimize with bit operations where possible.

class Solution {
public:
    int minimumCoins(vector<int>& a, int k) {
        sort(a.begin(), a.end());
        int n = a.size();
        vector<int> pf(n + 1, 0);
        for (int i = 0; i < n; i++) pf[i + 1] = pf[i] + a[i];
        int res = pf[n];
        for (int i = 0, j = 0; i < n; i++) {
            while (j < n && a[j] - a[i] <= k) j++;
            res = min(res, pf[i] + max(0, (pf[n] - pf[j]) - (n - j) * (a[i] + k)));
        }
        return res;
    }
};

๐Ÿ“ Complexity Analysis:

  • Time: โฑ๏ธ O(n log n)

  • Auxiliary Space: ๐Ÿ’พ O(n)

โœ… Why This Approach?

  • Cleaner mathematical operations.

  • Reduced function call overhead.

๐Ÿ†š ๐Ÿ” Comparison of Approaches

๐Ÿš€ Approach

โฑ๏ธ Time Complexity

๐Ÿ’พ Space Complexity

โœ… Pros

โš ๏ธ Cons

๐Ÿ” Ultra-Optimized Sliding

๐ŸŸข O(n log n)

๐ŸŸข O(1)

โšก Minimal memory, fastest runtime

๐Ÿงฎ Single-letter variables

๐Ÿ”„ Two Pointer Approach

๐ŸŸข O(n log n)

๐ŸŸข O(1)

๐Ÿ”ง Clear logic separation

๐Ÿข Slightly more operations

๐Ÿ“Š Deque Window

๐ŸŸข O(n log n)

๐Ÿ”ธ O(n)

๐ŸŽ๏ธ Explicit window management

๐Ÿ’พ Extra space overhead

๐Ÿงฎ Mathematical Optimization

๐ŸŸข O(n log n)

๐Ÿ”ธ O(n)

๐Ÿ“ˆ Clean mathematical operations

๐Ÿ’พ Prefix sum space

๐Ÿ† Best Choice Recommendation

๐ŸŽฏ Scenario

๐ŸŽ–๏ธ Recommended Approach

๐Ÿ”ฅ Performance Rating

โšก Maximum performance, memory critical

๐Ÿฅ‡ Ultra-Optimized Sliding

โ˜…โ˜…โ˜…โ˜…โ˜…

๐Ÿ”ง Code clarity with good performance

๐Ÿฅˆ Two Pointer Approach

โ˜…โ˜…โ˜…โ˜…โ˜†

๐ŸŽ๏ธ Educational/debugging purposes

๐Ÿฅ‰ Deque Window

โ˜…โ˜…โ˜…โ˜†โ˜†

๐Ÿ“Š Mathematical elegance

๐Ÿ… Mathematical Optimization

โ˜…โ˜…โ˜…โ˜…โ˜†

๐Ÿง‘โ€๐Ÿ’ป Code (Java)

class Solution {
    public int minimumCoins(int[] a, int k) {
        Arrays.sort(a);
        int n = a.length, t = Arrays.stream(a).sum(), res = t, w = 0, p = 0, e = 0;
        for (int s = 0; s < n; s++) {
            while (e < n && a[e] - a[s] <= k) w += a[e++];
            int r = Math.max(0, (t - p - w) - (n - e) * (a[s] + k));
            res = Math.min(res, p + r);
            if (e == s) e++; else w -= a[s];
            p += a[s];
        }
        return res;
    }
}

๐Ÿ Code (Python)

class Solution:
    def minimumCoins(self, a, k):
        a.sort()
        n, t, res, w, p, e = len(a), sum(a), sum(a), 0, 0, 0
        for s in range(n):
            while e < n and a[e] - a[s] <= k:
                w += a[e]
                e += 1
            r = max(0, (t - p - w) - (n - e) * (a[s] + k))
            res = min(res, p + r)
            if e == s: e += 1
            else: w -= a[s]
            p += a[s]
        return res

๐Ÿง  Contribution and Support

For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: ๐Ÿ“ฌ Any Questions?. Let's make this learning journey more collaborative!

โญ If you find this helpful, please give this repository a star! โญ


๐Ÿ“Visitor Count

Visitor counter

Last updated