1891. Cutting Ribbons π ο
Descriptionο
You are given an integer array ribbons
, where ribbons[i]
represents the length of the ith
ribbon, and an integer k
. You may cut any of the ribbons into any number of segments of positive integer lengths, or perform no cuts at all.
- For example, if you have a ribbon of length
4
, you can:<ul> <li>Keep the ribbon of length <code>4</code>,</li> <li>Cut it into one ribbon of length <code>3</code> and one ribbon of length <code>1</code>,</li> <li>Cut it into two ribbons of length <code>2</code>,</li> <li>Cut it into one ribbon of length <code>2</code> and two ribbons of length <code>1</code>, or</li> <li>Cut it into four ribbons of length <code>1</code>.</li> </ul> </li>
Your task is to determine the maximum length of ribbon, x
, that allows you to cut at least k
ribbons, each of length x
. You can discard any leftover ribbon from the cuts. If it is impossible to cut k
ribbons of the same length, return 0.
Example 1:
Input: ribbons = [9,7,5], k = 3 Output: 5 Explanation: - Cut the first ribbon to two ribbons, one of length 5 and one of length 4. - Cut the second ribbon to two ribbons, one of length 5 and one of length 2. - Keep the third ribbon as it is. Now you have 3 ribbons of length 5.
Example 2:
Input: ribbons = [7,5,9], k = 4 Output: 4 Explanation: - Cut the first ribbon to two ribbons, one of length 4 and one of length 3. - Cut the second ribbon to two ribbons, one of length 4 and one of length 1. - Cut the third ribbon to three ribbons, two of length 4 and one of length 1. Now you have 4 ribbons of length 4.
Example 3:
Input: ribbons = [5,7,9], k = 22 Output: 0 Explanation: You cannot obtain k ribbons of the same positive integer length.
Constraints:
1 <= ribbons.length <= 105
1 <= ribbons[i] <= 105
1 <= k <= 109
Solutionsο
Solution 1: Binary Searchο
We observe that if we can obtain $k$ ropes of length $x$, then we can also obtain $k$ ropes of length $x-1$. This implies that there is a monotonicity property, and we can use binary search to find the maximum length $x$ such that we can obtain $k$ ropes of length $x$.
We define the left boundary of the binary search as $left=0$, the right boundary as $right=\max(ribbons)$, and the middle value as $mid=(left+right+1)/2$. We then calculate the number of ropes we can obtain with length $mid$, denoted as $cnt$. If $cnt \geq k$, it means we can obtain $k$ ropes of length $mid$, so we update $left$ to $mid$. Otherwise, we update $right$ to $mid-1$.
Finally, we return $left$ as the maximum length of the ropes we can obtain.
The time complexity is $O(n \times \log M)$, where $n$ and $M$ are the number of ropes and the maximum length of the ropes, respectively. The space complexity is $O(1)$.
Python3ο
class Solution:
def maxLength(self, ribbons: List[int], k: int) -> int:
left, right = 0, max(ribbons)
while left < right:
mid = (left + right + 1) >> 1
cnt = sum(x // mid for x in ribbons)
if cnt >= k:
left = mid
else:
right = mid - 1
return left
Javaο
class Solution {
public int maxLength(int[] ribbons, int k) {
int left = 0, right = 0;
for (int x : ribbons) {
right = Math.max(right, x);
}
while (left < right) {
int mid = (left + right + 1) >>> 1;
int cnt = 0;
for (int x : ribbons) {
cnt += x / mid;
}
if (cnt >= k) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
}
C++ο
class Solution {
public:
int maxLength(vector<int>& ribbons, int k) {
int left = 0, right = *max_element(ribbons.begin(), ribbons.end());
while (left < right) {
int mid = (left + right + 1) >> 1;
int cnt = 0;
for (int ribbon : ribbons) {
cnt += ribbon / mid;
}
if (cnt >= k) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
};
Goο
func maxLength(ribbons []int, k int) int {
left, right := 0, slices.Max(ribbons)
for left < right {
mid := (left + right + 1) >> 1
cnt := 0
for _, x := range ribbons {
cnt += x / mid
}
if cnt >= k {
left = mid
} else {
right = mid - 1
}
}
return left
}
TypeScriptο
function maxLength(ribbons: number[], k: number): number {
let left = 0;
let right = Math.max(...ribbons);
while (left < right) {
const mid = (left + right + 1) >> 1;
let cnt = 0;
for (const x of ribbons) {
cnt += Math.floor(x / mid);
}
if (cnt >= k) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
Rustο
impl Solution {
pub fn max_length(ribbons: Vec<i32>, k: i32) -> i32 {
let mut left = 0i32;
let mut right = *ribbons.iter().max().unwrap();
while left < right {
let mid = (left + right + 1) / 2;
let mut cnt = 0i32;
for &entry in ribbons.iter() {
cnt += entry / mid;
if cnt >= k {
break;
}
}
if cnt >= k {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
}
JavaScriptο
/**
* @param {number[]} ribbons
* @param {number} k
* @return {number}
*/
var maxLength = function (ribbons, k) {
let left = 0;
let right = Math.max(...ribbons);
while (left < right) {
const mid = (left + right + 1) >> 1;
let cnt = 0;
for (const x of ribbons) {
cnt += Math.floor(x / mid);
}
if (cnt >= k) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
};