Question: https://codility.com/demo/take-sample-test/min_max_division

Question Name: Min-Max-Division or MinMaxDivision

Logically, it seems to be similar with the boron2013 (Flags) challenge by Codility. And the following is my Python solution.

**UPDATE** – 2014/09/19: thanks to Martin Kysel. The function signature is changed to:

def solution(K, M, A):

Don’t be confused by the new parameter M. Ignore the M, use the original solution, and you will pass all the test.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | def blocksNo(A, maxBlock): # Initially set the A[0] being an individual block blocksNumber = 1 # The number of blocks, that A could # be divided to with the restriction # that, the sum of each block is less # than or equal to maxBlock preBlockSum = A[0] for element in A[1:]: # Try to extend the previous block if preBlockSum + element > maxBlock: # Fail to extend the previous block, because # of the sum limitation maxBlock preBlockSum = element blocksNumber += 1 else: preBlockSum += element return blocksNumber def solution(K, A): blocksNeeded = 0 # Given the restriction on the sum of # each block, how many blocks could # the original A be divided to? resultLowerBound = max(A) resultUpperBound = sum(A) result = 0 # Minimal large sum # Handle two special cases if K == 1: return resultUpperBound if K >= len(A): return resultLowerBound # Binary search the result while resultLowerBound <= resultUpperBound: resultMaxMid = (resultLowerBound + resultUpperBound) / 2 blocksNeeded = blocksNo(A, resultMaxMid) if blocksNeeded <= K: # With large sum being resultMaxMid or resultMaxMid-, # we need blocksNeeded/blocksNeeded- blocks. While we # have some unused blocks (K - blocksNeeded), We could # try to use them to decrease the large sum. resultUpperBound = resultMaxMid - 1 result = resultMaxMid else: # With large sum being resultMaxMid or resultMaxMid-, # we need to use more than K blocks. So resultMaxMid # is impossible to be our answer. resultLowerBound = resultMaxMid + 1 return result |

In addition, thanks to @Guillermo (StackOverflow Profile), here is the C++ solution from @Guillermo, which inspired me. Thanks again for his sharing!

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | #include <cmath> int TestLargeSum(const std::vector < int > &A, int K,int LargeSum) { int i,n,j; n= A.size(); long long sum; sum=0; j=0; for (i=0;i < n;i++) { sum += A[i]; if (sum > LargeSum) { j++; if (j > (K-1)) return 0; sum =A[i]; } } return 1; } int solution(int K, vector < int > &A) { int i,n,Amax,LargeSum; int r,b,e,LargeSumR; n = A.size(); LargeSum=0; for (i=K-1; i < n; i++) LargeSum += A[i]; Amax=0; for (i=0;i < n;i++) if ( A[i] > Amax ) Amax=A[i]; if (K==n) return Amax; LargeSum= max(Amax,LargeSum); b= Amax; e= LargeSum; if (e < b) swap(e,b); LargeSumR=e; // BinSearch while (b <= e) { LargeSum = (b+e)/2; r = TestLargeSum(A,K,LargeSum); if ( r ) { e = LargeSum -1; LargeSumR= LargeSum; } else { b = LargeSum +1; } } return LargeSumR; } |

Java solution, greedy checking :

Thanks for sharing your solution. If it was with some key comments, it would be more helpful.

I am sorry. Everytime I access your website with Firefox, the page makes FF die. I have to remove it for security consideration for my visitors.

Hey Sheng,

there has been a change to the function signature which I fixed but your solution nevertheless no longer works https://codility.com/demo/results/demoDJSP8K-U9H/

I get the same errors and can not explain them.

Fixed:

http://www.martinkysel.com/codility-minmaxdivision-solution/

https://codility.com/demo/results/demo2T4UKQ-EPS/

They introduced M to confuse us! 😀

Your implementation is correct, I made false assumptions when porting it!

That is fine. And thank for telling me the change to the function signature.

I will add some explanation to help the others to understand the solutions.

I’m confused regarding the time complexity. Why is the time complexity O(N*log(N+M)) instead of O(N*log(N*M))? The upper bound of the binary search is equal to the sum of the elements in A, which is at most N*M.

Yes, you are right. The complexity is not exactly O(N*log(N+M)). O(N*log(N*M)) = O(N*(log(N) + log(M))). Therefore, when N is close to M, O(N*log(N*M)) is the same as O(N*log(N+M)). In generaly case, I do not know the answer.

“when N is close to M, O(N*log(N*M)) is the same as O(N*log(N+M))”

this seems wrong…

Thank you very much for your solution. Really enlightening 🙂

Here’s the Java version of your Python solution:

What is throwing me off is that the exercise is asking for “expected worst-case time complexity is O(N*log(N+M))”

If I’m reading your solution correctly you’re first looping through all the elements followed by the binary search section. Isn’t that O(n) + log(n+m) ?

You are partly right. The binary search at #37 is inside the while loop around #35: so the complexity is O(N) * O(log(N+M)) = O(N*log(N+M)).

I was tricked by M…”no greater than M” made me made the assumption that the largest element in the array must be M, which is not true, well, at least in Codility test cases. I got 43% just because of failing to recognize this “fact”…

If we consider the smallest max as a monotonic sequence, the lower bound of the sequence is the largest element in the array, and the higher bound is the sum of all elements. Then we choose the possible “smallest max” at the middle of the sequence and always greedily drops half of of the sequence by comparing the number of partitions based upon current “smallest max” with the proposed K. If our partition L is less than K, we probably can find a even smaller “smallest max” by dropping the lager half of the sequence, otherwise, drop the smaller half…

Agree that the parameter M is misleading.

M is not misleading. In fact it can be proved that the result is between (mean，mean+M).

Updated by Sailingfish on Aug 19, 2017.

The initial lower bound could be max( sum(A)/K, max(A) )

In the sample given in the question; K=3, A=[2, 1, 5, 1, 2, 2, 2] should the answer not be 5 instead of the given answer 6? You can group the elements as [2,2,1].[2,2,1],[5]

>> “You should divide this array into K blocks of consecutive elements.”

You cannot shuffle the input array. Thanks!

Sheng, thank you for great work!

I have one question, how can you prove that resultMaxMid is the minimal large sum?

Essentially, the solution is a binary search among all possible answers. So yes, we get the right answer 🙂

To better understand the solution, you could read the official answer for a very similar question boron2013 (Flags) : https://codility.com/media/train/solution-flags.pdf

Great work. I am always inspired by your ideas and skills.

For those who are still studying in 2021, you need to get the ceiling value of the average like this (using the ceil from math)