def maxLength(self, ribbons,k): max_rib = max(ribbons) search = FakeArray(max_rib) key = partial(total_ribbons, ribbons = ribbons) position = bisect.bisect_left(search, k, key = key) #The if block here just handles the boundary cases... It doesn't really add to the algo. if position==0: return len(search) elif position == len(search): return 0 else: return len(search)-position
def maxLength(self, ribbons: List[int], k: int) -> int: if sum(ribbons) < k: return 0 # we will not able to make k ribbons # think about binary search left and right index left, right = 1, max(ribbons) while left < right: # a classical way of finding the largest index by binary search mid = (left+right) // 2 + 1 # think of getting the value at index mid cuts = sum([ribbon // mid for ribbon in ribbons]) if cuts >= k: left = mid elif cuts < k: right = mid-1 return right
def maxLength(self, ribbons: List[int], k: int) -> int: minPossible = 1 # minimum possible ribbon length maxPossible = max(ribbons) # maximum possible ribbon length while minPossible <= maxPossible: currentLength = minPossible+(maxPossible-minPossible)//2 # length of current try numOfPiecesWithcurrentLength = 0 for ribbon in ribbons: # getting number of possible ribbons with current length numOfPiecesWithcurrentLength += ribbon//currentLength if numOfPiecesWithcurrentLength >= k: # we have longer pieces than we need so we can try longer lengths == increase lower bound (minPossible) minPossible = currentLength + 1 else: maxPossible = currentLength - 1 return maxPossible
def maxLength(self, ribbons: List[int], k: int) -> int: s = sum(ribbons) # impossible case: when total length sum of all ribbons are less than `k` if s < k: return 0 n = len(ribbons) def ok(mid): # is it `ok` to form `k` ribbon with length `mid`? nonlocal ribbons, k cnt = 0 for r in ribbons: cnt += r // mid return cnt >= k l, r = 1, max(ribbons) while l <= r: # binary search mid = (l+r) // 2 if ok(mid): l = mid + 1 else: r = mid - 1 return r
def maxLength(self, ribbons: List[int], k: int) -> int: # The minumum length of the ribbon that we can cut is 1 start = 1 # The maximum length of the ribbon can be the maximum element in the list end = max(ribbons) # In this binary search, we are trying to go through the origin list and figure out which integer(from 1 -> ribbon of max length) is the deired length for the the target k pieces while(start <= end): mid = start + (end - start) // 2 res = 0 for i in ribbons: res += i // mid # If the value is >= target, we know that there could be a larger integer that will satisfy the same conditon if res >= k: start = mid+1 else: # If lesser than k, then there could be a value lesser than the mid that could satisfy the condition end = mid -1 return end
numOfPiecesWithcurrentLength += ribbon//currentLength if numOfPiecesWithcurrentLength >= k: # we have longer pieces than we need so we can try longer lengths == increase lower bound (minPossible) minPossible = currentLength + 1 else: maxPossible = currentLength - 1 return maxPossible ------------------------------------------------------------------------------------ Brute Force The problem asks us to the max length of k ribbons. Lets first consider what lengths can we get. We know that min length is 1 (e.g, ribbons = [3], k = 3). If we could not get length 1 (e.g. ribbons = [2], k = 3), then we return 0. Now the max length is a bit tricky, at first, I though it is min(ribbons). based on the example ribbons = [9,7,5], k = 3. However, we can easily find a counter example ribbons = [10,10,1], k = 2 there is a similar test case, this one is simplified. Problem is simple now, just go from 1 to max(ribbons), find the largest length with the number of ribbons == k. Problem solved with time complexity O(max(ribbons)) Binary Search Can we do better? Yes! If you think through the problem, we are given some index [1, max(ribbons)], and we want to find the largest index such that length2ribbon[index] == k (I will explain the meaning of the array latter). Sounds familiar? If such an array length2ribbon is sorted, we could use binary search! The real question is whether the array is sorted? Fortunately, yes it is. length2ribbon is the array containing number of ribbons we get if we use length index to cut them. More formally, we calculate the array by [float('inf')] + [sum([ribbon // length for ribbon in ribbons]) for length in range(1, max(ribbons))]. Its a bit complicated, but essentially, the number at index i is the number of ribbons we get if we are using length i to cut. The first term is the correction for 1 indexed array. We can easily prove that this array is non increasing.(when you are cutting with a larger length, it is not possible to get more ribbons!) This means we can do binary search on it. This is the basic idea why we are legitimate to do binary search. In most answers, including the code I give, we do not actually construct the array as I have mentioned above becuase it is not necessary. But it is nice to reason yourself out why you can do binary search on sth that does not seems like an array. Here is my code, ask questions if I do not explain it clearly! Hope it is helpful. Binary search is a lard topic! I find it challening for a long time. Try to solve problem https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/, carefully reason through why your code works by loop invariant! class Solution: def maxLength(self, ribbons: List[int], k: int) -> int: if sum(ribbons) < k: