First of all, big O notation gives us an idea about the relation between two functions t(n)/i(n) when n -> infinity. To be more specific, it's an upper bound for such relation, which means it's f(n) >= t(n)/i(n). t(n) stands for the speed of growth of time spent on execution, i(n) describes the speed of growth of input. In function space (we work with functions there rather than with numbers and treat functions almost like numbers: we can divide or compare them, for example) the relation between two elements is also a function. Hence, t(n)/i(n) is a function.

Secondly, there are two methods of determining bounds for that relation.

The scientific observational approach implies the next steps. Let's see how much time it takes to execute an algorithm with 10 pieces of input. Then let's increase the input up to 100 pieces, and then up to 1000 and so on. The speed of growth of input i(n) is exponential (10^1, 10^2, 10^3, ...). Suppose, we get the exponential speed of growth of time as well (10^1 sec, 10^2 sec, 10^3 sec, ... respectively).

That means t(n)/i(n) = exp(n)/exp(n) = 1, n -> infinity (for the scientific purity sake, we can divide and compare functions only when n -> infinity, it doesn't mean anything for the practicality of the method though). We can say at least (remember it's an upper bound) the execution time of our algorithm doesn't grow faster than its input does. We might have got, say, the quadratic exponential speed of growth of time. In that case t(n)/i(n) = exp^2(n)/exp(n) = a^2n/a^n = exp(n), a > 1, n -> infinity, which means our time complexity is O(exp(n)), big O notation only reminds us that it's not a tight bound. Also, it's worth pointing out that it doesn't matter which speed of growth of input we choose. We might have wanted to increase our input linearly. Then t(n)/i(n) = exp(n)*n/n = exp(n) would express the same as t(n)/i(n) = exp^2(n)/exp(n) = a^2n/a^n = exp(n), a > 1. What matters here is the quotient.

The second approach is theoretical and mostly used in the analysis of relatively obvious cases. Say, we have a piece of code from the example:

// DP Table 
static int [][][]dp = new int[500][500][500]; 
   
// Function to count the number 
// of ways to divide the number N 
// in groups such that each group 
// has K number of elements 
static int calculate(int pos, int prev,  
                 int left, int k) 
{ 
    // Base Case 
    if (pos == k)  
    { 
        if (left == 0) 
            return 1; 
        else
            return 0; 
    } 
    
    // if N is divides completely  
    // into less than k groups 
    if (left == 0) 
        return 0; 
   
    // If the subproblem has been 
    // solved, use the value 
    if (dp[pos][prev][left] != -1) 
        return dp[pos][prev][left]; 
   
    int answer = 0; 
    
    // put all possible values  
    // greater equal to prev 
    for (int i = prev; i <= left; i++)  
    { 
        answer += calculate(pos + 1, i,  
                           left - i, k); 
    } 
   
    return dp[pos][prev][left] = answer; 
} 

// Function to count the number of  
// ways to divide the number N in groups 
static int countWaystoDivide(int n, int k) 
{ 
    // Intialize DP Table as -1 
        for (int i = 0; i < 500; i++)  
        { 
            for (int j = 0; j < 500; j++) 
            { 
                for (int l = 0; l < 500; l++) 
                    dp[i][j][l] = -1; 
            } 
        } 
   
    return calculate(0, 1, n, k); 
} 

The first thing to notice here is a 3-d array dp. It gives us a hint of the time complexity of a DP algorithm because usually, we traverse it once. Then we are concerned about the size of the array. It's initialized with the size 500*500*500 which doesn't give us a lot because 500 is a number, not a function, and it doesn't depend on the input variables, strictly speaking. It's done for the sake of simplicity though. Effectively, the dp has size of k*n*n with assumption that k <= 500 and n <= 500.

Let's prove it. Method static int calculate(int pos, int prev, int left, int k) has three actual variables pos, prev and left when k remains constant. The range of pos is 0 to k because it starts from 0 here return calculate(0, 1, n, k); and the base case is if (pos == k), the range of prev is 1 to left because it starts from 1 and iterates through up to left here for (int i = prev; i <= left; i++) and finally the range of left is n to 0 because it starts from n here return calculate(0, 1, n, k); and iterates through down to 0 here for (int i = prev; i <= left; i++). To recap, the number of possible combinations of pos, prev and left is simply their product k*n*n.

The second thing is to prove that each range of pos, prev and left is traversed only once. From the code, it can be determined by analysing this block:

for (int i = prev; i <= left; i++)  
{ 
    answer += calculate(pos + 1, i,  
                       left - i, k); 
}

All the 3 variables get changed only here. pos grows from 0 by adding 1 on each step. On each particular value of pos, prev gets changed by adding 1 from prev up to left, on each particular combination of values of pos and prev, left gets changed by subtracting i, which has the range prev to left, from left.

The idea behind this approach is once we iterate over an input variable by some rule, we get corresponding time complexity. We could iterate over a variable stepping on elements by decreasing the range by twice on each step, for example. In that case, we would get logarithmical complexity. Or we could step on every element of the input, then we would get linear complexity.

In other words, we without any doubts assume the minimum time complexity t(n)/i(n) = 1 for every algorithm from common sense. Meaning that t(n) and i(n) grow equally fast. That also means we do nothing with the input. Once we do something with the input, t(n) becomes f(n) times bigger than i(n). By the logic shown in the previous lines, we need to estimate f(n).

Answer from Evgeny Mamaev on Stack Overflow
🌐
HackerRank
hackerrank.com › contests › world-codesprint-13 › challenges › group-formation
Group Formation | World CodeSprint 13 Question | Contests
Find the largest group after possibly granting some requests. Solving code challenges on HackerRank is one of the best ways to prepare for programming interviews.
🌐
Stupidtechy
stupidtechy.me › threads › group-division-java-hackerrank-solution.200
Loading...
November 19, 2021 - We cannot provide a description for this page right now
Top answer
1 of 1
3

First of all, big O notation gives us an idea about the relation between two functions t(n)/i(n) when n -> infinity. To be more specific, it's an upper bound for such relation, which means it's f(n) >= t(n)/i(n). t(n) stands for the speed of growth of time spent on execution, i(n) describes the speed of growth of input. In function space (we work with functions there rather than with numbers and treat functions almost like numbers: we can divide or compare them, for example) the relation between two elements is also a function. Hence, t(n)/i(n) is a function.

Secondly, there are two methods of determining bounds for that relation.

The scientific observational approach implies the next steps. Let's see how much time it takes to execute an algorithm with 10 pieces of input. Then let's increase the input up to 100 pieces, and then up to 1000 and so on. The speed of growth of input i(n) is exponential (10^1, 10^2, 10^3, ...). Suppose, we get the exponential speed of growth of time as well (10^1 sec, 10^2 sec, 10^3 sec, ... respectively).

That means t(n)/i(n) = exp(n)/exp(n) = 1, n -> infinity (for the scientific purity sake, we can divide and compare functions only when n -> infinity, it doesn't mean anything for the practicality of the method though). We can say at least (remember it's an upper bound) the execution time of our algorithm doesn't grow faster than its input does. We might have got, say, the quadratic exponential speed of growth of time. In that case t(n)/i(n) = exp^2(n)/exp(n) = a^2n/a^n = exp(n), a > 1, n -> infinity, which means our time complexity is O(exp(n)), big O notation only reminds us that it's not a tight bound. Also, it's worth pointing out that it doesn't matter which speed of growth of input we choose. We might have wanted to increase our input linearly. Then t(n)/i(n) = exp(n)*n/n = exp(n) would express the same as t(n)/i(n) = exp^2(n)/exp(n) = a^2n/a^n = exp(n), a > 1. What matters here is the quotient.

The second approach is theoretical and mostly used in the analysis of relatively obvious cases. Say, we have a piece of code from the example:

// DP Table 
static int [][][]dp = new int[500][500][500]; 
   
// Function to count the number 
// of ways to divide the number N 
// in groups such that each group 
// has K number of elements 
static int calculate(int pos, int prev,  
                 int left, int k) 
{ 
    // Base Case 
    if (pos == k)  
    { 
        if (left == 0) 
            return 1; 
        else
            return 0; 
    } 
    
    // if N is divides completely  
    // into less than k groups 
    if (left == 0) 
        return 0; 
   
    // If the subproblem has been 
    // solved, use the value 
    if (dp[pos][prev][left] != -1) 
        return dp[pos][prev][left]; 
   
    int answer = 0; 
    
    // put all possible values  
    // greater equal to prev 
    for (int i = prev; i <= left; i++)  
    { 
        answer += calculate(pos + 1, i,  
                           left - i, k); 
    } 
   
    return dp[pos][prev][left] = answer; 
} 

// Function to count the number of  
// ways to divide the number N in groups 
static int countWaystoDivide(int n, int k) 
{ 
    // Intialize DP Table as -1 
        for (int i = 0; i < 500; i++)  
        { 
            for (int j = 0; j < 500; j++) 
            { 
                for (int l = 0; l < 500; l++) 
                    dp[i][j][l] = -1; 
            } 
        } 
   
    return calculate(0, 1, n, k); 
} 

The first thing to notice here is a 3-d array dp. It gives us a hint of the time complexity of a DP algorithm because usually, we traverse it once. Then we are concerned about the size of the array. It's initialized with the size 500*500*500 which doesn't give us a lot because 500 is a number, not a function, and it doesn't depend on the input variables, strictly speaking. It's done for the sake of simplicity though. Effectively, the dp has size of k*n*n with assumption that k <= 500 and n <= 500.

Let's prove it. Method static int calculate(int pos, int prev, int left, int k) has three actual variables pos, prev and left when k remains constant. The range of pos is 0 to k because it starts from 0 here return calculate(0, 1, n, k); and the base case is if (pos == k), the range of prev is 1 to left because it starts from 1 and iterates through up to left here for (int i = prev; i <= left; i++) and finally the range of left is n to 0 because it starts from n here return calculate(0, 1, n, k); and iterates through down to 0 here for (int i = prev; i <= left; i++). To recap, the number of possible combinations of pos, prev and left is simply their product k*n*n.

The second thing is to prove that each range of pos, prev and left is traversed only once. From the code, it can be determined by analysing this block:

for (int i = prev; i <= left; i++)  
{ 
    answer += calculate(pos + 1, i,  
                       left - i, k); 
}

All the 3 variables get changed only here. pos grows from 0 by adding 1 on each step. On each particular value of pos, prev gets changed by adding 1 from prev up to left, on each particular combination of values of pos and prev, left gets changed by subtracting i, which has the range prev to left, from left.

The idea behind this approach is once we iterate over an input variable by some rule, we get corresponding time complexity. We could iterate over a variable stepping on elements by decreasing the range by twice on each step, for example. In that case, we would get logarithmical complexity. Or we could step on every element of the input, then we would get linear complexity.

In other words, we without any doubts assume the minimum time complexity t(n)/i(n) = 1 for every algorithm from common sense. Meaning that t(n) and i(n) grow equally fast. That also means we do nothing with the input. Once we do something with the input, t(n) becomes f(n) times bigger than i(n). By the logic shown in the previous lines, we need to estimate f(n).

🌐
GitHub
github.com › srgnk › HackerRank
GitHub - srgnk/HackerRank: Solutions to HackerRank problems · GitHub
Solutions to HackerRank problems. Contribute to srgnk/HackerRank development by creating an account on GitHub.
Starred by 457 users
Forked by 223 users
Languages   Python 85.2% | C 7.8% | C++ 5.4% | Shell 1.6%
🌐
HackerRank
hackerrank.com › challenges › team-formation › problem
Team Formation | HackerRank
For the first case, Roy can form two teams: one with contestants with skill levels {-4,-3,-5} and the other one with {4,5,2,3}. The first group containing 3 members is the smallest.
🌐
Programmingoneonone
programmingoneonone.com › home › hackerrank stone division problem solution
HackerRank Stone Division problem solution
January 26, 2026 - import java.io.*; import java.math.*; import java.text.*; import java.util.*; import java.util.regex.*; public class Solution { public static long zero = 0L; static int findMex(HashSet<Integer> grundys){ int mex = 0; while(grundys.contains(mex)){ mex++; } return mex; } static int getGrundy(long n, long[] s, Hashtable<Long, Integer> grundyVals){ if (n == zero){ return 0; } else if (grundyVals.containsKey(n)){ return grundyVals.get(n); } else{ HashSet<Integer>nextPositions = new HashSet<Integer>(); for (int i = 0; i < s.length; i++){ if (n % s[i] == zero){ long pilesize = n/s[i]; int g = 0; if(s
🌐
HackerEarth
hackerearth.com › problem › algorithm › hp-and-counting-number-of-ways-1-2808c854
Two Groups | Practice Problems
Prepare for your technical interviews by solving questions that are asked in interviews of various companies. HackerEarth is a global hub of 5M+ developers. We help companies accurately assess, interview, and hire top developers for a myriad of roles.
Find elsewhere
🌐
GitHub
github.com › habdalnaser › HackerRank_Solutions › blob › main › Java › Subarray Division › Solution.java
HackerRank_Solutions/Java/Subarray Division/Solution.java at main · habdalnaser/HackerRank_Solutions
Hacker rank problem solving practicing solutions. Contribute to habdalnaser/HackerRank_Solutions development by creating an account on GitHub.
Author   habdalnaser
🌐
GeeksforGeeks
geeksforgeeks.org › dsa › count-the-number-of-ways-to-divide-n-in-k-groups-incrementally
Count the number of ways to divide N in k groups incrementally - GeeksforGeeks
July 12, 2025 - Initialize a 2-D array dp[][] of size n+1, k+1 where dp[i][j] will store the optimal solution to divide n into k groups.
🌐
GitHub
github.com › Noor-Abdhulla-A › Bill-Division
GitHub - Noor-Abdhulla-A/Bill-Division: Hackerrank Problem Solution in java
Hackerrank Problem Solution in java. Contribute to Noor-Abdhulla-A/Bill-Division development by creating an account on GitHub.
Author   Noor-Abdhulla-A
🌐
GitHub
github.com › tanvirul15 › Divide-And-Conquer
GitHub - tanvirul15/Divide-And-Conquer: My solution of divide and conquer method problems in hackerrank. This includes quick short, merge short, MaximmumSubArrayBruit, and a few more.
My solution of divide and conquer method problems in hackerrank. This includes quick short, merge short, MaximmumSubArrayBruit, and a few more. - tanvirul15/Divide-And-Conquer
Author   tanvirul15
🌐
HackerRank
hackerrank.com › challenges › kingdom-division › problem
Kingdom Division | HackerRank
The King wants to divide his kingdom between his two children, Reggie and Betty, by giving each of them or more cities; however, they don't get along so he must divide the kingdom in such a way that they will not invade each other's cities. The first sibling will invade the second sibling's city if the second sibling has no other cities directly connected to it.
🌐
Peesafe
stores.peesafe.com › 5po5rw › group-division-hackerrank-leetcode.html
Peesafe
April 9, 2022 - Group division hackerrank leetcode. Trainee Software Developer at IsDB-BISEW . tree-height-of-a-binary-tree hackerrank Solution - Optimal, Correct and Working. Got hackerrank test. A company is not hiring you to invert a binary tree. Activities and Societies: I am a problem solver.
🌐
HackerRank
hackerrank.com › challenges › kingdom-division › forum
Kingdom Division Discussions | Algorithms | HackerRank
for the dfs function return pair, ... node color same as parent (eg. never be lonely no matter of what children colors) dfs(1, -1) means that we start from node 1 as root, and no parent for the root node 1, because it has ...
🌐
Blogoncode
blogoncode.com › 2021 › 08 › subarray-division-java-solution.html
Subarray Division HackerRank solution in Java with examples
Two children, Lily and Ron, want to share a chocolate bar. Each of the squares has an integer on it.Lily decides to share a contiguous segment of t...
🌐
GitHub
github.com › sknsht › HackerRank
GitHub - sknsht/HackerRank: My solutions to HackerRank problems
Solutions to problems on HackerRank · Java · Python · SQL · Cracking the Coding Interview · Interview Preparation Kit · Functional Programming · Subdomain · Challenge · Score · Difficulty · Solution · Introduction · Welcome to Java! 3 · Easy · Solution.java ·
Starred by 286 users
Forked by 188 users
Languages   Java 81.5% | Python 16.4% | C++ 1.3% | Java 81.5% | Python 16.4% | C++ 1.3%
🌐
GitHub
github.com › RyanFehr › HackerRank
GitHub - RyanFehr/HackerRank: HackerRank solutions in Java/JS/Python/C++/C#
HackerRank solutions in Java/JS/Python/C++/C#. Contribute to RyanFehr/HackerRank development by creating an account on GitHub.
Starred by 1.3K users
Forked by 692 users
Languages   Java 46.6% | C# 43.8% | JavaScript 4.6% | C++ 3.0% | Python 2.0% | Java 46.6% | C# 43.8% | JavaScript 4.6% | C++ 3.0% | Python 2.0%
🌐
GitHub
github.com › injamul3798 › Hackerrank-solution
GitHub - injamul3798/Hackerrank-solution: Coding Practice
Coding Practice . Contribute to injamul3798/Hackerrank-solution development by creating an account on GitHub.
Author   injamul3798