The problem statement is :
Given an integer array A of size N.
You can pick B elements from either left or right end of the array A to get maximum sum.
Find and return this maximum possible sum.
NOTE: Suppose B = 4 and array A contains 10 elements then:
You can pick first four elements or can pick last four elements or can pick 1 from front and 3 from back etc . you need to return the maximum possible sum of elements you can pick.
public class Solution {
ArrayList<Integer> c = new ArrayList<>();
ArrayList<Integer> A= new ArrayList<>();
public int solve(ArrayList<Integer> A, int B) {
if (B>A.size()){
int sum=0;
for(int i=0;i<A.size();i++)
sum= sum+A.get(i);
return sum;
}
int max_sum=0;
for(int i=0;i<A.size();i++){
if((max_sum<suffix(A.size()-(B-i))+prefix(i-1)) ){
max_sum=suffix(A.size()-(B-i))+prefix(i-1);
}
}
return max_sum;
}
int prefix_sum=0;
int prefix(int a) {
for(int p=0;p<a+1;p++){
c=A;
prefix_sum=prefix_sum + c.get(p);
}
return prefix_sum;
}
int suffix_sum=0;
int suffix(int b){
c=A;
for(int q=b;q<c.size();q++){
suffix_sum=suffix_sum+c.get(q);
}
return suffix_sum;
}
}
I am getting runtime error, I have tried to implement the suffix and prefix methods which return the sum from the index[ 0, i] and sum from [i, N-i] respectively, then in the solve function I am trying to find the sum of prefix [a-1] +suffix[N-(b-a)] and find out the maximum sum, the syntax is completely correct, there is something wrong with the logic I assume, please help me find the correct solution by correcting this code instead of providing an alternative method
package com.array;
import java.util.Arrays;
import java.util.List;
public class PickFromBothSides {
public static void main(String[] args) {
Integer[] arr = { 5, -2, 3, 1, 2 };
System.out.println(solve(Arrays.asList(arr), 3));
}
public static int solve(List<Integer> A, int B) {
int n = A.size();
int result = 0;
for (int i = 0; i < B; i++) {
result += A.get(i);
}
int sum = result;
for (int i = 0; i < B; i++) {
sum -= A.get(B - 1 - i);
sum += A.get(n - 1 - i);
result = Math.max(result, sum);
}
return result;
}
}
Runtime O(n)
Space complexity O(1)
You are declaring int prefix_sum=0; and int suffix_sum=0; as fields, not as local variables of the respective methods.
You are calling suffix(A.size()-(B-i)) so with your example that is 10 - (4 -i) which is 6 + i. You iterate through i being in the range {0, ..., 10} so the value 6 + i will be all the numbers 6 through 16. You cannot index in the array above 9, so you get an exception.
You need to change
for(int i=0;i<A.size();i++){
to
for(int i=0; i <= B; i++){
because you are trying to ask each iteration "how many numbers are taken from the beginning"? 0, 1, 2, 3 or 4 if B is 4
Other upgrades:
You are calling suffix(A.size()-(B-i))+prefix(i-1)) twice in a row. Call it only once, store it in a variable and reuse.
You are calling prefix(i-1) but inside prefix() you are using the parameter a as a + 1. You don't need to subtract one and add one to the same thing
Related
The Bruteforce approach to find the shortest subsequence length for a given sum is giving the correct 2,2,9 outputs for the inputs given in the main method but when memoized getting wrong output 3,3,9. Can anyone help with this please? Thanks.
class ShortestSubsequenceWithSum {
public static int shortestSubsequenceWithSum(int[] num, int s, int cnt, Integer []dp) {
if(s == 0){
return cnt;
}
if(s < 0){
return Integer.MAX_VALUE;
}
if(dp[s] != null){
return dp[s];
}
int res = Integer.MAX_VALUE;
for(int i=0; i<num.length; i++){
int rem = s - num[i];
int ways = shortestSubsequenceWithSum(num, rem, cnt +1, dp);
res = Math.min(res, ways);
dp[s] = res;
}
// System.out.println("Returning value at # " + s);
return dp[s];
}
public static void main(String[] args) {
int[] num = {1, 1, 2, 3};
Integer dp[] = new Integer[5+1];
System.out.println(shortestSubsequenceWithSum(num, 5,0, dp));
num = new int[]{1, 2, 7, 1};
dp = new Integer[9+1];
System.out.println(shortestSubsequenceWithSum(num, 9,0, dp));
num = new int[]{1};
dp = new Integer[9+1];
System.out.println(shortestSubsequenceWithSum(num, 9,0, dp));
}
}
The problem here is that the way your recursive method works at present isn't amenable to memoization.
It looks like you are using your dp array to store the currently-known minimum count of numbers required to make a total. So dp[5] will be the minimum count of numbers required to make a total of 5. If dp[5] = 3 then you have found a way to make a total of 5 from three numbers, but not yet found a way to make 5 from fewer than three numbers.
Your method shortestSubsequenceWithSum presently returns the minimum count of numbers required to reach the total plus the number of recursive calls currently made. If you want to use memoization you will have to adjust this method to return the minimum count of numbers required to reach the total, regardless of how many levels of recursion there have so far been.
The changes you will need to make are:
In the handling for the case s == 0, return 0 rather than cnt. This represents being able to make a total of 0 from zero numbers.
Change the line dp[s] = res to dp[s] = res + 1. res contains the (minimum) count of numbers that make up s - num[i] for each value of i so far, so we add 1 for choosing num[i] in a combination that adds up to s.
These should be enough to get your code working. However, you can in fact move the line dp[s] = res + 1 immediately outside the for loop: we may as well wait for the final value of res before assigning it to dp[s]. You can also remove the parameter cnt from your method shortestSubsequenceWithSum, and all the calls to this method, as this parameter isn't being used any more.
This should leave you with the following:
/**
* Returns the minimum count of numbers from the given array that can
* make up a total. The same number can be chosen multiple times.
* #param num The numbers that can be chosen from.
* #param s The total to reach.
* #param dp An array that memoizes pre-computed values of this method.
* #return The minimum count of numbers from 'num' that totals 's'.
*/
public static int shortestSubsequenceWithSum(int[] num, int s, Integer []dp) {
if(s == 0){
return 0;
}
if(s < 0){
return Integer.MAX_VALUE;
}
if(dp[s] != null){
return dp[s];
}
int res = Integer.MAX_VALUE;
for(int i=0; i<num.length; i++){
int rem = s - num[i];
int ways = shortestSubsequenceWithSum(num, rem, dp);
res = Math.min(res, ways);
}
dp[s] = res + 1;
// System.out.println("Returning value at # " + s);
return dp[s];
}
Finally, I'll note that this code does not handle the case that there are no combinations that add up to the total. I'll leave fixing that as an exercise for you, see below for an example test case:
int[] num = {2, 4, 6};
Integer dp[] = new Integer[5+1];
System.out.println(shortestSubsequenceWithSum(num, 5, dp));
I am a beginner(first year uni student) programmer trying to solve this problem which i'm finding somewhat difficult. If you are to answer this question, don't provide me with a complex daunting algorithm that will leave me scratching my head. I'll really appreciate it if you explain it step my step (both logically/conceptually then through code)
The problem is as follows:image
I have tried to attempt it and my code only works for a certain case that i tested.
package com.company;
import java.lang.Math;
public class Main {
public static int[][] binary_partition(int array[], int k){
int x = (int) Math.pow(2,k);
int[][] partition = new int[((array.length/x)*2)][array.length/x];
int divisor = array.length/x;
if ((array.length % 2) != 0){
return partition;
}
if (divisor >= array.length-1){
return partition;
}
if (k==1){
return partition;
}
int p = 0;
for(int i=0;i<((array.length/x)*2);i++)
{
for (int j = 0; j<array.length/x;j++)
{
partition[i][j] = array[p];
p += 1;
}
}
return partition;
}
public static void main(String[] args){
int[] array = {3, 2, 4, 7, 8, 9, 2, 3};
int[][] result = binary_partition(array,2);
for (int[] x : result){
for (int y : x)
{
System.out.print(y + " ");
}
System.out.println();
}
}
}
Your question is unclear, but this solution creates a function that partitions an array with the right length into 2^k sets.
First, an interesting fact: using the bitshift operator << on an integer increases its value by a power of two. So to find out the size of your partition, you could write
int numPartitions = 1 << k; // Equivalent to getting the integer value of 2^k
With this fact, the function becomes
public static int[][] partition(int[] set, int k) {
if (set == null)
return null; // Don't try to partition a null reference
// If k = 0, the partition of the set is just the set
if (k == 0) {
int[][] partition = new int[1][set.length];
// Copy the original set into the partition
System.arraycopy(set, 0, partition[0], 0, set.length);
return partition;
}
int numPartitions = 1 << k; // The number of sets to partition the array into
int numElements = set.length / numPartitions; // The number of elements per partition
/* Check if the set has enough elements to create a partition and make sure
that the partitions are even */
if (numElements == 0 || set.length % numElements != 0)
return null; // Replace with an error/exception of your choice
int[][] partition = new int[numPartitions][numElements];
int index = 0;
for (int r = 0; r < numPartitions; r++) {
for (int c = 0; c < numElements; c++) {
partition[r][c] = set[index++]; // Assign an element to the partition
}
}
return partition;
}
There are a few lines of your code where the intention is not clear. For example, it is not clear why you are validating divisor >= array.length-1. Checking k==1 is also incorrect because k=1 is a valid input to the method. In fact, all your validation checks are not needed. All you need to validate is that array.length is divisible by x.
The main problem that you have seems to be that you mixed up the lengths of the resulting array.
The resulting array should have a length of array.length / x, and each of the subarrays should have a length of x, hence:
int[][] partition = new int[array.length/x][x];
If you also fix your bounds on the for loops, your code should work.
Your nested for loop can be rewritten as a single for loop:
for(int i = 0 ; i < array.length ; i++)
{
int index = i / x;
int subArrayIndex = i % x;
partition[index][subArrayIndex] = array[i];
}
You just need to figure out which indices a an element array[i] belongs by dividing and getting the remainder.
I'm looking a simple solution to get the minimum number "ArrayList of Integers" needed to have all numbers from 1 to n, with the next condition:
Each ArrayList must be created from 3 parameters (a, b and n)
"a" and "b" set the numbers in the ArrayList
"n" is the limit
The condition is:
If a ≤ b ===> a ≤ j ≤ b
if a>b ===> 1 ≤ j ≤ b and a ≤ j ≤ n
Note: "j" are the numbers on the ArrayList.
this is my code:
public Integers(int a, int b, int n) {//constructor
this.numbers = new ArrayList<Integer>();
makeList(a, b, n);
}
public void makeList(int a, int b, int n) {
if (a < b) {
while (a <= b) {
this.numbers.add(a);
a++;
}
} else {
int aux = 1;
while (aux <= b) {
this.numbers.add(aux);
aux++;
}
int aux2 = a;
while (aux2 <= n) {
this.numbers.add(aux2);
aux2++;
}
}
}
public void showNumbers() {
for (int x = 0; x < this.numbers.size(); x++) {
System.out.print(this.numbers.get(x) + "\t");
}
}
this is an example with n=20:
public static void main(String[] args) {
Integers first= new Integers(1, 10, 20);
first.showNumbers();//1 2 3 ...8 9 10
System.out.println();
Integers second= new Integers(15, 5, 20);
second.showNumbers();//1 2 3 4 5 15 16 17 18 19 20
System.out.println();
Integers third= new Integers(15, 20, 20);
third.showNumbers();//15 16 17 18 19 20
System.out.println();
Integers fourth= new Integers(4, 17, 20);
fourth.showNumbers();//4 5 6 ... 15 16 17
System.out.println();
System.out.println("Solution expected is: 2 ====> <second and fourth>");
}
and the answer that I expect is 2 (second and fourth).
If you know what n is from the start, it might be simpler to store a boolean array of n values. Then every time you construct an ArrayList, you just mark off if that value would appear in the ArrayList.
Other than this, you pretty much would have to brute-force (I think this would be equivalent to the vertex-cover problem so you'd at best be able to approximate in faster times than brute-forcing).
Hence, I'd try this implementation of your Integer class:
public class Integer {
private int a, b;
private boolean flipped;
public Integer(int _a, int _b){
a = Math.min(_a, _b);
b = Math.max(_a, _b);
flipped = b < a;
}
public void markOff(boolean [] arr){
for(int i = 0; i < arr.length; i++){
if(a <= i && i <= b){
arr[i] = arr[i] || !flipped;
}else{
arr[i] = arr[i] || flipped;
}
}
}
}
So in the above, markOff just checks if each index would appear in the ArrayList you'd create (I'll leave figuring out the boolean logic up to you, but the idea is just to set all the extra elements to true as necessary - so if a new index is covered by the array, you'd mark it off, but you don't un-mark already marked ones.) You can optimize it to not traverse the whole array and look more like your makeList if you want to.
In order to find the minimal set of arrays that would cover up to n, you'd have to do something like the following:
public static int driveSoln(int n, Integer[] covers){
return helper(covers, new boolean[n], 0, 0);
}
private static int helper(Integer[] covers, boolean[] marked, int idx, int used){
boolean done;
for(boolean d: marked) done = done && d;
if(done) return used;
if(idx >= covers.length) return -1;
boolean [] markCopy = marked.clone();
covers[i].markOff(marked);
int dontUse = helper(covers, markCopy, idx + 1, used);
int use = helper(covers, marked, idx + 1, used + 1);
return Math.min(use, dontUse);
}
Intuitively, what I do here is for each inputted cover, chose whether or not to use it and keep looking at the rest. The recursion here "remembers" my choices. I'm guaranteed to (sadly) check all the choices, so this is quite slow, but definitely right. An optimization might be to ignore subsets: if an array only covers items already covered by 1 array, discard it.
Given an integer array, which is sorted (in increasing order) and has been rotated by some number k in clockwise direction. Find and return the k.
code written by me is as below..
im getting wrong results.
public class CheckRotation {
public static int arrayRotateCheck(int[] arr){
/* Your class should be named CheckRotation
* Don't write main().
* Don't read input, it is passed as function argument.
* Return output and don't print it.
* Taking input and printing output is handled automatically.
*/
int s=0;
int next=0;
int prev=0;
int mid=0;
int n = arr.length-1;
while(s<=n)
{
mid= s+(n-s)/2;
next=(mid+1)%n;
prev=(mid-1)%n;
if(arr[s]<=arr[n])
{
return s;
}
if(arr[mid]<=next && arr[mid]<=prev)
{
return mid;
}
if(arr[mid]<arr[n])
n= mid-1;
if(arr[mid]>arr[s])
s= mid +1;
}
return Integer.MAX_VALUE;
}
}
If I'm understanding your question correctly, if an assorted array is rotated clockwise, all the elements shift to the left. So basically [1, 2, 3, 4] becomes [2, 3, 4, 1]. And you're trying to find k being the number it was moved by. In that example, it would be 1. If so, here's a solution:
public static int RotationCheck(int[] numArray) {
int smallest = Integer.MAX_VALUE;
int k = 0;
//Finding the smallest int
for(int num: numArray) {
if(smallest > num)
smallest = num;
}
//Getting new index of smallest int
for(int i=0;i<numArray.length;i++) {
if(numArray[i] == smallest)
k = numArray.length - i;
}
return k;
}
I first find the smallest value then check its position in the array. Since the array is sorted, the smallest number would originally be the first index.
I'm solving Codility questions as practice and couldn't answer one of the questions. I found the answer on the Internet but I don't get how this algorithm works. Could someone walk me through it step-by-step?
Here is the question:
/*
You are given integers K, M and a non-empty zero-indexed array A consisting of N integers.
Every element of the array is not greater than M.
You should divide this array into K blocks of consecutive elements.
The size of the block is any integer between 0 and N. Every element of the array should belong to some block.
The sum of the block from X to Y equals A[X] + A[X + 1] + ... + A[Y]. The sum of empty block equals 0.
The large sum is the maximal sum of any block.
For example, you are given integers K = 3, M = 5 and array A such that:
A[0] = 2
A[1] = 1
A[2] = 5
A[3] = 1
A[4] = 2
A[5] = 2
A[6] = 2
The array can be divided, for example, into the following blocks:
[2, 1, 5, 1, 2, 2, 2], [], [] with a large sum of 15;
[2], [1, 5, 1, 2], [2, 2] with a large sum of 9;
[2, 1, 5], [], [1, 2, 2, 2] with a large sum of 8;
[2, 1], [5, 1], [2, 2, 2] with a large sum of 6.
The goal is to minimize the large sum. In the above example, 6 is the minimal large sum.
Write a function:
class Solution { public int solution(int K, int M, int[] A); }
that, given integers K, M and a non-empty zero-indexed array A consisting of N integers, returns the minimal large sum.
For example, given K = 3, M = 5 and array A such that:
A[0] = 2
A[1] = 1
A[2] = 5
A[3] = 1
A[4] = 2
A[5] = 2
A[6] = 2
the function should return 6, as explained above. Assume that:
N and K are integers within the range [1..100,000];
M is an integer within the range [0..10,000];
each element of array A is an integer within the range [0..M].
Complexity:
expected worst-case time complexity is O(N*log(N+M));
expected worst-case space complexity is O(1), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
*/
And here is the solution I found with my comments about parts which I don't understand:
public static int solution(int K, int M, int[] A) {
int lower = max(A); // why lower is max?
int upper = sum(A); // why upper is sum?
while (true) {
int mid = (lower + upper) / 2;
int blocks = calculateBlockCount(A, mid); // don't I have specified number of blocks? What blocks do? Don't get that.
if (blocks < K) {
upper = mid - 1;
} else if (blocks > K) {
lower = mid + 1;
} else {
return upper;
}
}
}
private static int calculateBlockCount(int[] array, int maxSum) {
int count = 0;
int sum = array[0];
for (int i = 1; i < array.length; i++) {
if (sum + array[i] > maxSum) {
count++;
sum = array[i];
} else {
sum += array[i];
}
}
return count;
}
// returns sum of all elements in an array
private static int sum(int[] input) {
int sum = 0;
for (int n : input) {
sum += n;
}
return sum;
}
// returns max value in an array
private static int max(int[] input) {
int max = -1;
for (int n : input) {
if (n > max) {
max = n;
}
}
return max;
}
So what the code does is using a form of binary search (How binary search works is explained quite nicely here, https://www.topcoder.com/community/data-science/data-science-tutorials/binary-search/. It also uses an example quite similar to your problem.). Where you search for the minimum sum every block needs to contain. In the example case, you need the divide the array in 3 parts
When doing a binary search you need to define 2 boundaries, where you are certain that your answer can be found in between. Here, the lower boundary is the maximum value in the array (lower). For the example, this is 5 (this is if you divide your array in 7 blocks). The upper boundary (upper) is 15, which is the sum of all the elements in the array (this is if you divide the array in 1 block.)
Now comes the search part: In solution() you start with your bounds and mid point (10 for the example).
In calculateBlockCount you count (count ++ does that) how many blocks you can make if your sum is a maximum of 10 (your middle point/ or maxSum in calculateBlockCount).
For the example 10 (in the while loop) this is 2 blocks, now the code returns this (blocks) to solution. Then it checks whether is less or more than K, which is the number of blocks you want. If its less than K your mid point is high because you're putting to many array elements in your blocks. If it's more than K, than your mid point is too high and you're putting too little array elements in your array.
Now after the checking this, it halves the solution space (upper = mid-1).
This happens every loop, it halves the solution space which makes it converge quite quickly.
Now you keep going through your while adjusting the mid, till this gives the amount blocks which was in your input K.
So to go though it step by step:
Mid =10 , calculateBlockCount returns 2 blocks
solution. 2 blocks < K so upper -> mid-1 =9, mid -> 7 (lower is 5)
Mid =7 , calculateBlockCount returns 2 blocks
solution() 2 blocks < K so upper -> mid-1 =6, mid -> 5 (lower is 5, cast to int makes it 5)
Mid =5 , calculateBlockCount returns 4 blocks
solution() 4 blocks < K so lower -> mid+1 =6, mid -> 6 (lower is 6, upper is 6
Mid =6 , calculateBlockCount returns 3 blocks
So the function returns mid =6....
Hope this helps,
Gl learning to code :)
Edit. When using binary search a prerequisite is that the solution space is a monotonic function. This is true in this case as when K increases the sum is strictly decreasing.
Seems like your solution has some problems. I rewrote it as below:
class Solution {
public int solution(int K, int M, int[] A) {
// write your code in Java SE 8
int high = sum(A);
int low = max(A);
int mid = 0;
int smallestSum = 0;
while (high >= low) {
mid = (high + low) / 2;
int numberOfBlock = blockCount(mid, A);
if (numberOfBlock > K) {
low = mid + 1;
} else if (numberOfBlock <= K) {
smallestSum = mid;
high = mid - 1;
}
}
return smallestSum;
}
public int sum(int[] A) {
int total = 0;
for (int i = 0; i < A.length; i++) {
total += A[i];
}
return total;
}
public int max(int[] A) {
int max = 0;
for (int i = 0; i < A.length; i++) {
if (max < A[i]) max = A[i];
}
return max;
}
public int blockCount(int max, int[] A) {
int current = 0;
int count = 1;
for (int i = 0; i< A.length; i++) {
if (current + A[i] > max) {
current = A[i];
count++;
} else {
current += A[i];
}
}
return count;
}
}
This is helped me in case anyone else finds it helpful.
Think of it as a function: given k (the block count) we get some largeSum.
What is the inverse of this function? It's that given largeSum we get a k. This inverse function is implemented below.
In solution() we keep plugging guesses for largeSum into the inverse function until it returns the k given in the exercise.
To speed up the guessing process, we use binary search.
public class Problem {
int SLICE_MAX = 100 * 1000 + 1;
public int solution(int blockCount, int maxElement, int[] array) {
// maxGuess is determined by looking at what the max possible largeSum could be
// this happens if all elements are m and the blockCount is 1
// Math.max is necessary, because blockCount can exceed array.length,
// but this shouldn't lower maxGuess
int maxGuess = (Math.max(array.length / blockCount, array.length)) * maxElement;
int minGuess = 0;
return helper(blockCount, array, minGuess, maxGuess);
}
private int helper(int targetBlockCount, int[] array, int minGuess, int maxGuess) {
int guess = minGuess + (maxGuess - minGuess) / 2;
int resultBlockCount = inverseFunction(array, guess);
// if resultBlockCount == targetBlockCount this is not necessarily the solution
// as there might be a lower largeSum, which also satisfies resultBlockCount == targetBlockCount
if (resultBlockCount <= targetBlockCount) {
if (minGuess == guess) return guess;
// even if resultBlockCount == targetBlockCount
// we keep searching for potential lower largeSum that also satisfies resultBlockCount == targetBlockCount
// note that the search range below includes 'guess', as this might in fact be the lowest possible solution
// but we need to check in case there's a lower one
return helper(targetBlockCount, array, minGuess, guess);
} else {
return helper(targetBlockCount, array, guess + 1, maxGuess);
}
}
// think of it as a function: given k (blockCount) we get some largeSum
// the inverse of the above function is that given largeSum we get a k
// in solution() we will keep guessing largeSum using binary search until
// we hit k given in the exercise
int inverseFunction(int[] array, int largeSumGuess) {
int runningSum = 0;
int blockCount = 1;
for (int i = 0; i < array.length; i++) {
int current = array[i];
if (current > largeSumGuess) return SLICE_MAX;
if (runningSum + current <= largeSumGuess) {
runningSum += current;
} else {
runningSum = current;
blockCount++;
}
}
return blockCount;
}
}
From anhtuannd's code, I refactored using Java 8. It is slightly slower. Thanks anhtuannd.
IntSummaryStatistics summary = Arrays.stream(A).summaryStatistics();
long high = summary.getSum();
long low = summary.getMax();
long result = 0;
while (high >= low) {
long mid = (high + low) / 2;
AtomicLong blocks = new AtomicLong(1);
Arrays.stream(A).reduce(0, (acc, val) -> {
if (acc + val > mid) {
blocks.incrementAndGet();
return val;
} else {
return acc + val;
}
});
if (blocks.get() > K) {
low = mid + 1;
} else if (blocks.get() <= K) {
result = mid;
high = mid - 1;
}
}
return (int) result;
I wrote a 100% solution in python here. The result is here.
Remember: You are searching the set of possible answers not the array A
In the example given they are searching for possible answers. Consider [5] as 5 being the smallest max value for a block. And consider [2, 1, 5, 1, 2, 2, 2] 15 as the largest max value for a block.
Mid = (5 + 15) // 2. Slicing out blocks of 10 at a time won't create more than 3 blocks in total.
Make 10-1 the upper and try again (5+9)//2 is 7. Slicing out blocks of 7 at a time won't create more than 3 blocks in total.
Make 7-1 the upper and try again (5+6)//2 is 5. Slicing out blocks of 5 at a time will create more than 3 blocks in total.
Make 5+1 the lower and try again (6+6)//2 is 6. Slicing out blocks of 6 at a time won't create more than 3 blocks in total.
Therefore 6 is the lowest limit to impose on the sum of a block that will permit breaking into 3 blocks.