Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1891. Cutting Ribbons - Leetcode Solution

Code Implementation

class Solution:
    def maxLength(self, ribbons, k):
        def count(mid):
            return sum(r // mid for r in ribbons)
        
        left, right = 1, max(ribbons)
        result = 0
        while left <= right:
            mid = (left + right) // 2
            if count(mid) >= k:
                result = mid
                left = mid + 1
            else:
                right = mid - 1
        return result
      
class Solution {
public:
    int maxLength(vector<int>& ribbons, int k) {
        int left = 1, right = *max_element(ribbons.begin(), ribbons.end());
        int result = 0;
        auto count = [&](int len) {
            int total = 0;
            for (int r : ribbons) total += r / len;
            return total;
        };
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (count(mid) >= k) {
                result = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return result;
    }
};
      
class Solution {
    public int maxLength(int[] ribbons, int k) {
        int left = 1, right = 0;
        for (int r : ribbons) right = Math.max(right, r);
        int result = 0;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            int count = 0;
            for (int r : ribbons) count += r / mid;
            if (count >= k) {
                result = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return result;
    }
}
      
var maxLength = function(ribbons, k) {
    let left = 1, right = Math.max(...ribbons);
    let result = 0;
    const count = (len) => ribbons.reduce((acc, r) => acc + Math.floor(r / len), 0);
    while (left <= right) {
        const mid = Math.floor((left + right) / 2);
        if (count(mid) >= k) {
            result = mid;
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return result;
};
      

Problem Description

You are given an array ribbons where each element represents the length of a ribbon, and an integer k. Your task is to cut the ribbons into pieces such that you get exactly k or more pieces, and all pieces are of the same positive integer length. You can cut any ribbon as many times as you want or even leave it unused. The goal is to find the maximum possible integer length for these pieces.

  • Each piece must be of the same length.
  • Each ribbon can be used multiple times (by cutting), or not at all.
  • Return the maximum integer length possible so that at least k pieces of that length can be obtained. If it is not possible, return 0.

Key Constraints:

  • There may be multiple ribbons of different lengths.
  • You must not "combine" ribbons; each piece must come from a single ribbon.
  • There is always at most one valid solution for the maximum length.

Thought Process

At first glance, the problem seems to invite a brute-force approach: try every possible piece length from 1 up to the length of the longest ribbon, and for each, check if you can cut at least k pieces of that length. However, this is inefficient, especially for large inputs.

On closer inspection, we realize that increasing the piece length will decrease the number of pieces we can get, and vice versa. This monotonic property suggests the use of binary search: we can efficiently home in on the largest possible length by checking, for a given length, whether it's possible to get at least k pieces.

The key insight is to shift from checking every length (brute-force) to using the binary search technique to minimize the number of checks and speed up the process.

Solution Approach

Let's break down the optimized solution step by step:

  1. Set Search Bounds: The shortest possible piece is 1, and the longest possible piece is the length of the longest ribbon (since you can't have a piece longer than any ribbon).
  2. Binary Search: Use binary search between 1 and the maximum ribbon length to find the largest length that allows at least k pieces.
    • For each candidate length mid, compute how many pieces you can get by dividing each ribbon by mid (using integer division).
    • If the total is at least k, it means you can try a longer length, so move the lower bound up.
    • If the total is less than k, try shorter lengths by moving the upper bound down.
  3. Counting Helper: For a given length, sum up ribbon_length // mid for all ribbons to find how many pieces you can make.
  4. Result: Keep track of the largest length for which you can get at least k pieces. Return this value at the end.

This approach is efficient because each binary search iteration reduces the search space by half, and counting the pieces is a simple linear operation.

Example Walkthrough

Suppose ribbons = [9, 7, 5] and k = 3. Let's find the maximum possible length.

  1. Set bounds: left = 1, right = 9 (max ribbon).
  2. First binary search:
    • mid = (1 + 9) // 2 = 5
    • Pieces: 9//5 = 1, 7//5 = 1, 5//5 = 1, total = 3
    • 3 pieces is enough, so try longer: left = 6, result = 5
  3. Second binary search:
    • mid = (6 + 9) // 2 = 7
    • Pieces: 9//7 = 1, 7//7 = 1, 5//7 = 0, total = 2
    • Not enough, try shorter: right = 6
  4. Third binary search:
    • mid = (6 + 6) // 2 = 6
    • Pieces: 9//6 = 1, 7//6 = 1, 5//6 = 0, total = 2
    • Not enough, try shorter: right = 5
  5. End: left > right, so the answer is result = 5.

The largest length is 5, and we can get exactly 3 pieces of length 5.

Time and Space Complexity

  • Brute-force Approach:
    • Try all possible lengths from 1 to max(ribbons), for each length, sum up pieces (O(n) per length).
    • Total time: O(n * max(ribbons)). This can be slow if ribbons are large.
  • Optimized (Binary Search) Approach:
    • Binary search over possible lengths: O(log(max(ribbons))).
    • For each binary search step, count pieces: O(n).
    • Total time: O(n * log(max(ribbons))).
    • Space: O(1) extra, since we just use a few variables (not counting input).

The binary search approach is much more efficient and works well even for large arrays and large ribbon lengths.

Summary

The Cutting Ribbons problem is elegantly solved using binary search. By leveraging the monotonic relationship between piece length and the number of pieces, we can efficiently find the maximum possible length for the pieces. The key insight is to avoid brute-force enumeration and instead use binary search to minimize the number of checks. This strategy ensures both correctness and efficiency, making the solution suitable for large input sizes.