Geek is standing at a point (x, y) on a 2D grid and wants to reach the origin (0, 0). From any point, Geek can move in only two directions: left, from (x, y) to (x - 1, y), or down, from (x, y) to (x, y - 1).
Find the total number of distinct paths for Geek to reach (0, 0) from (x, y). Since the answer can be very large, return it modulo 1000000007.
[Naive Approach] Using Recursion - O(2^(x+y)) Time and O(x+y) Space
We can use Recursion to simulate every possible path.
At any given coordinate, we have two choices:
Take a step left
Take a step down.
We branch out into both possibilities and add their results together.
If we hit the boundaries (where either the x or y coordinate becomes 0), there is only one straight line left to the origin, so we return 1.
C++
#include<iostream>usingnamespacestd;intways(intx,inty){intmod=1000000007;// Reached a boundary, only one straight path leftif(x==0||y==0){return1;}// Branch into moving left and downreturn(ways(x-1,y)+ways(x,y-1))%mod;}intmain(){intx=3,y=6;cout<<ways(x,y)<<endl;return0;}
Java
classGFG{publicstaticintways(intx,inty){intmod=1000000007;// Reached a boundary, only one straight path leftif(x==0||y==0){return1;}// Branch into moving left and downreturn(ways(x-1,y)+ways(x,y-1))%mod;}publicstaticvoidmain(String[]args){intx=3,y=6;System.out.println(ways(x,y));}}
Python
defways(x,y):mod=1000000007# Reached a boundary, only one straight path leftifx==0ory==0:return1# Branch into moving left and downreturn(ways(x-1,y)+ways(x,y-1))%modif__name__=="__main__":x=3y=6print(ways(x,y))
C#
usingSystem;classGFG{publicstaticintways(intx,inty){intmod=1000000007;// Reached a boundary, only one straight path leftif(x==0||y==0){return1;}// Branch into moving left and downreturn(ways(x-1,y)+ways(x,y-1))%mod;}publicstaticvoidMain(){intx=3,y=6;Console.WriteLine(ways(x,y));}}
JavaScript
functionways(x,y){letmod=1000000007;// Reached a boundary, only one straight path leftif(x===0||y===0){return1;}// Branch into moving left and downreturn(ways(x-1,y)+ways(x,y-1))%mod;}// Driver Codeletx=3;lety=6;console.log(ways(x,y));
Output
84
[Better Approach] 2D Dynamic Programming - O(x * y) Time and O(x * y) Space
To avoid recalculating the same paths, we can use 2D Dynamic Programming (Tabulation). Think of the grid as a spreadsheet where each cell stores the total number of ways to reach it from the origin.
Since you can only move left or down to reach the origin, working in reverse means to reach cell (i, j) from the origin, you can only come from the cell directly below it (i, j-1) or the cell directly to its left (i-1, j). We can build a 2D matrix where the value of any cell is simply the sum of the cell to its left and the cell below it.
C++
#include<iostream>#include<vector>usingnamespacestd;intways(intx,inty){intmod=1000000007;// Create a 2D matrix initialized to 0vector<vector<int>>dp(x+1,vector<int>(y+1,0));// Base cases for bordersfor(inti=0;i<=x;i++)dp[i][0]=1;for(intj=0;j<=y;j++)dp[0][j]=1;// Fill the matrixfor(inti=1;i<=x;i++){for(intj=1;j<=y;j++){// Add top and left pathsdp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;}}returndp[x][y];}intmain(){intx=3,y=6;cout<<ways(x,y)<<endl;return0;}
Java
classGFG{publicstaticintways(intx,inty){intmod=1000000007;// Create a 2D matrix initialized to 0int[][]dp=newint[x+1][y+1];// Base cases for bordersfor(inti=0;i<=x;i++)dp[i][0]=1;for(intj=0;j<=y;j++)dp[0][j]=1;// Fill the matrixfor(inti=1;i<=x;i++){for(intj=1;j<=y;j++){// Add top and left pathsdp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;}}returndp[x][y];}publicstaticvoidmain(String[]args){intx=3,y=6;System.out.println(ways(x,y));}}
Python
defways(x,y):mod=1000000007# Create a 2D matrix initialized to 0dp=[[0]*(y+1)for_inrange(x+1)]# Base cases for bordersforiinrange(x+1):dp[i][0]=1forjinrange(y+1):dp[0][j]=1# Fill the matrixforiinrange(1,x+1):forjinrange(1,y+1):# Add top and left pathsdp[i][j]=(dp[i-1][j]+dp[i][j-1])%modreturndp[x][y]if__name__=="__main__":x=3y=6print(ways(x,y))
C#
usingSystem;classGFG{publicstaticintways(intx,inty){intmod=1000000007;// Create a jagged 2D matrixint[][]dp=newint[x+1][];for(inti=0;i<=x;i++){dp[i]=newint[y+1];dp[i][0]=1;}// Base cases for bordersfor(intj=0;j<=y;j++){dp[0][j]=1;}// Fill the matrixfor(inti=1;i<=x;i++){for(intj=1;j<=y;j++){// Add top and left pathsdp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;}}returndp[x][y];}publicstaticvoidMain(){intx=3,y=6;Console.WriteLine(ways(x,y));}}
JavaScript
functionways(x,y){letmod=1000000007;// Create a 2D matrix initialized to 0letdp=Array.from({length:x+1},()=>Array(y+1).fill(0));// Base cases for bordersfor(leti=0;i<=x;i++)dp[i][0]=1;for(letj=0;j<=y;j++)dp[0][j]=1;// Fill the matrixfor(leti=1;i<=x;i++){for(letj=1;j<=y;j++){// Add top and left pathsdp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;}}returndp[x][y];}// Driver Codeletx=3;lety=6;console.log(ways(x,y));
Output
84
[Expected Approach] Space Optimized DP - O(x * y) Time and O(y) Space
If we look closely at the 2D Dynamic Programming table, computing the current row only requires the values from the immediately preceding row.
We can simplify the logic and optimize the memory by collapsing the 2D grid into a single 1D array representing just one row. As we scan from left to right, we update the array in place.
The value currently at dp[j] represents the cell directly above (from the previous row), and dp[j-1] represents the freshly calculated cell directly to the left. Adding them together gives us the new value for the current cell.
Example: x = 2, y = 2
Initialization: Create a 1D array dp of size y + 1 (size 3) and fill it with 1s. This represents row 0. dp = [1, 1, 1].
Result: The loop finishes. The final value at dp[y] is 6. Return 6.
C++
#include<iostream>#include<vector>usingnamespacestd;intways(intx,inty){intmod=1000000007;// Create a 1D array to store the previous row valuesvector<int>dp(y+1,1);// Build the paths row by rowfor(inti=1;i<=x;i++){for(intj=1;j<=y;j++){// Current cell = top cell (dp[j]) + left cell (dp[j-1])dp[j]=(dp[j]+dp[j-1])%mod;}}returndp[y];}intmain(){intx=3,y=6;cout<<ways(x,y)<<endl;return0;}
Java
importjava.util.*;classGFG{publicstaticintways(intx,inty){intmod=1000000007;// Create a 1D array to store the previous row valuesint[]dp=newint[y+1];Arrays.fill(dp,1);// Build the paths row by rowfor(inti=1;i<=x;i++){for(intj=1;j<=y;j++){// Current cell = top cell (dp[j]) + left cell (dp[j-1])dp[j]=(dp[j]+dp[j-1])%mod;}}returndp[y];}publicstaticvoidmain(String[]args){intx=3,y=6;System.out.println(ways(x,y));}}
Python
defways(x,y):mod=1000000007# Create a 1D array to store the previous row valuesdp=[1]*(y+1)# Build the paths row by rowforiinrange(1,x+1):forjinrange(1,y+1):# Current cell = top cell (dp[j]) + left cell (dp[j-1])dp[j]=(dp[j]+dp[j-1])%modreturndp[y]if__name__=="__main__":x=3y=6print(ways(x,y))
C#
usingSystem;classGFG{publicstaticintways(intx,inty){intmod=1000000007;// Create a 1D array to store the previous row valuesint[]dp=newint[y+1];for(inti=0;i<=y;i++){dp[i]=1;}// Build the paths row by rowfor(inti=1;i<=x;i++){for(intj=1;j<=y;j++){// Current cell = top cell (dp[j]) + left cell (dp[j-1])dp[j]=(dp[j]+dp[j-1])%mod;}}returndp[y];}publicstaticvoidMain(){intx=3,y=6;Console.WriteLine(ways(x,y));}}
JavaScript
functionways(x,y){letmod=1000000007;// Create a 1D array to store the previous row valuesletdp=newArray(y+1).fill(1);// Build the paths row by rowfor(leti=1;i<=x;i++){for(letj=1;j<=y;j++){// Current cell = top cell (dp[j]) + left cell (dp[j-1])dp[j]=(dp[j]+dp[j-1])%mod;}}returndp[y];}// Driver Codeletx=3;lety=6;console.log(ways(x,y));
Output
84
[Optimal Approach] Combinatorics - O(min(x, y) * log(mod)) Time and O(1) Space
To reach (0, 0) from (x, y), Geek must make exactly x left moves and y down moves. The total number of moves will always be exactly x + y. Any valid path is simply a unique arrangement of these x left moves and y down moves.
This translates perfectly to a combinatorics problem: out of the total (x + y) steps, we just need to choose x positions for the left moves (or y positions for the down moves). Mathematically, this is (x + y) C x. To calculate this efficiently under modulo 10^9+7 without overflow, we compute the combinations iteratively and use Fermat's Little Theorem to handle the division (modular multiplicative inverse).
Let n = x + y (total moves) and r = min(x, y) (minimum moves to choose, to optimize the loop).
Initialize ans = 1.
Loop i from 1 to r. In standard math, nCr multiplies by (n - i + 1) and divides by i.
Multiply ans by (n - i + 1) and take modulo.
Instead of standard division by i, calculate the modular inverse of i using Fermat's Little Theorem: power(i, mod - 2).
Multiply ans by this modular inverse and take modulo.
After the loop, return the final calculated combination.
For example, x = 2 and y = 2
Total moves n = 2 + 2 = 4. We need to choose r = min(2, 2) = 2. We calculate 4C2.
Iteration i = 1: Multiply ans by (4 - 1 + 1) = 4. Divide by 1. ans becomes 4.
Iteration i = 2: Multiply ans by (4 - 2 + 1) = 3. Divide by 2. ans becomes (4 * 3) / 2 = 6.
Result: The loop finishes. The total number of paths is 6.
C++
#include<iostream>#include<algorithm>usingnamespacestd;// Helper to calculate (base^exp) % modlonglongpower(longlongbase,longlongexp){longlongres=1;longlongmod=1000000007;base=base%mod;while(exp>0){if(exp%2==1){res=(res*base)%mod;}base=(base*base)%mod;exp/=2;}returnres;}// Helper to find modular inverse using Fermat's Little TheoremlonglongmodInverse(longlongn){returnpower(n,1000000007-2);}intways(intx,inty){longlongmod=1000000007;intn=x+y;intr=min(x,y);longlongans=1;// Calculate nCr % modfor(inti=1;i<=r;i++){// Multiply by (n - i + 1)ans=(ans*(n-i+1))%mod;// Divide by i using modular inverseans=(ans*modInverse(i))%mod;}return(int)ans;}intmain(){intx=3,y=6;cout<<ways(x,y)<<endl;return0;}
Java
classGFG{// Helper to calculate (base^exp) % modpublicstaticlongpower(longbase,longexp){longres=1;longmod=1000000007;base=base%mod;while(exp>0){if(exp%2==1){res=(res*base)%mod;}base=(base*base)%mod;exp/=2;}returnres;}// Helper to find modular inverse using Fermat's Little TheorempublicstaticlongmodInverse(longn){returnpower(n,1000000007-2);}publicstaticintways(intx,inty){longmod=1000000007;intn=x+y;intr=Math.min(x,y);longans=1;// Calculate nCr % modfor(inti=1;i<=r;i++){// Multiply by (n - i + 1)ans=(ans*(n-i+1))%mod;// Divide by i using modular inverseans=(ans*modInverse(i))%mod;}return(int)ans;}publicstaticvoidmain(String[]args){intx=3,y=6;System.out.println(ways(x,y));}}
Python
# Helper to calculate (base^exp) % moddefpower(base,exp):res=1mod=1000000007base=base%modwhileexp>0:ifexp%2==1:res=(res*base)%modbase=(base*base)%modexp//=2returnres# Helper to find modular inverse using Fermat's Little TheoremdefmodInverse(n):returnpower(n,1000000007-2)defways(x,y):mod=1000000007n=x+yr=min(x,y)ans=1# Calculate nCr % modforiinrange(1,r+1):# Multiply by (n - i + 1)ans=(ans*(n-i+1))%mod# Divide by i using modular inverseans=(ans*modInverse(i))%modreturnansif__name__=="__main__":x=3y=6print(ways(x,y))
C#
usingSystem;classGFG{// Helper to calculate (base^exp) % modpublicstaticlongPower(longbaseVal,longexp){longres=1;longmod=1000000007;baseVal=baseVal%mod;while(exp>0){if(exp%2==1){res=(res*baseVal)%mod;}baseVal=(baseVal*baseVal)%mod;exp/=2;}returnres;}// Helper to find modular inverse using Fermat's Little TheorempublicstaticlongModInverse(longn){returnPower(n,1000000007-2);}publicstaticintways(intx,inty){longmod=1000000007;intn=x+y;intr=Math.Min(x,y);longans=1;// Calculate nCr % modfor(inti=1;i<=r;i++){// Multiply by (n - i + 1)ans=(ans*(n-i+1))%mod;// Divide by i using modular inverseans=(ans*ModInverse(i))%mod;}return(int)ans;}publicstaticvoidMain(){intx=3,y=6;Console.WriteLine(ways(x,y));}}
JavaScript
// Helper to calculate (base^exp) % mod safely using BigIntfunctionpower(base,exp){letres=1n;letmod=1000000007n;base=BigInt(base)%mod;exp=BigInt(exp);while(exp>0n){if(exp%2n===1n){res=(res*base)%mod;}base=(base*base)%mod;exp/=2n;}returnres;}// Helper to find modular inverse using Fermat's Little TheoremfunctionmodInverse(n){returnpower(n,1000000007-2);}functionways(x,y){letmod=1000000007n;letn=x+y;letr=Math.min(x,y);letans=1n;// Calculate nCr % modfor(leti=1;i<=r;i++){letbigI=BigInt(i);// Multiply by (n - i + 1)ans=(ans*BigInt(n-i+1))%mod;// Divide by i using modular inverseans=(ans*modInverse(bigI))%mod;}returnNumber(ans);}// Driver Codeletx=3;lety=6;console.log(ways(x,y));