Before attempting this problem, you should be comfortable with:
Dynamic Programming - Used to count valid ways by tracking seat counts in each section
Memoization - Caching subproblem results to avoid redundant computation
Modular Arithmetic - Required for handling large results modulo 10^9+7
Combinatorics - The optimal approach counts divider positions between seat pairs using multiplication
1. Dynamic Programming (Top-Down)
Intuition
We need to divide the corridor so each section has exactly two seats. The key insight is that after placing two seats in a section, we have a choice: place the divider immediately after the second seat, or delay it through any number of plants. Each plant between the second seat of one section and the first seat of the next section represents a possible divider position.
Algorithm
Define a recursive function dfs(i, seats) where i is the current index and seats counts how many seats are in the current section (0, 1, or 2).
Base case: If we reach the end of the corridor, return 1 if we have exactly 2 seats (valid section), otherwise 0.
If we already have 2 seats in the current section:
If the current position is a seat, we must start a new section (reset seats to 1).
If it's a plant, we can either place the divider here (reset to 0) or continue without dividing (keep at 2).
If we have fewer than 2 seats, count the seat if present and continue.
classSolution:defnumberOfWays(self, corridor:str)->int:
mod =10**9+7
cache =[[-1]*3for i inrange(len(corridor))]# (i, seats) -> countdefdfs(i, seats):if i ==len(corridor):return1if seats ==2else0if cache[i][seats]!=-1:return cache[i][seats]
res =0if seats ==2:if corridor[i]=="S":
res = dfs(i +1,1)else:
res =(dfs(i +1,0)+ dfs(i +1,2))% mod
else:if corridor[i]=="S":
res = dfs(i +1, seats +1)else:
res = dfs(i +1, seats)
cache[i][seats]= res
return res
return dfs(0,0)
publicclassSolution{privatestaticfinalintMOD=1_000_000_007;privateint[][] dp;publicintnumberOfWays(String corridor){int n = corridor.length();
dp =newint[n][3];for(int i =0; i < n; i++){Arrays.fill(dp[i],-1);}returndfs(0,0, corridor);}privateintdfs(int i,int seats,String corridor){if(i == corridor.length()){return seats ==2?1:0;}if(dp[i][seats]!=-1){return dp[i][seats];}int res =0;if(seats ==2){if(corridor.charAt(i)=='S'){
res =dfs(i +1,1, corridor);}else{
res =(dfs(i +1,0, corridor)+dfs(i +1,2, corridor))%MOD;}}else{if(corridor.charAt(i)=='S'){
res =dfs(i +1, seats +1, corridor);}else{
res =dfs(i +1, seats, corridor);}}return dp[i][seats]= res;}}
classSolution{public:staticconstexprint MOD =1'000'000'007;
vector<vector<int>> dp;intnumberOfWays(string corridor){int n = corridor.size();
dp.assign(n,vector<int>(3,-1));returndfs(0,0, corridor);}intdfs(int i,int seats, string& corridor){if(i == corridor.size()){return seats ==2?1:0;}if(dp[i][seats]!=-1){return dp[i][seats];}int res =0;if(seats ==2){if(corridor[i]=='S'){
res =dfs(i +1,1, corridor);}else{
res =(dfs(i +1,0, corridor)+dfs(i +1,2, corridor))% MOD;}}else{if(corridor[i]=='S'){
res =dfs(i +1, seats +1, corridor);}else{
res =dfs(i +1, seats, corridor);}}return dp[i][seats]= res;}};
classSolution{/**
* @param {string} corridor
* @return {number}
*/numberOfWays(corridor){constMOD=1_000_000_007;const n = corridor.length;const dp = Array.from({length: n },()=>Array(3).fill(-1));constdfs=(i, seats)=>{if(i === n)return seats ===2?1:0;if(dp[i][seats]!==-1)return dp[i][seats];let res =0;if(seats ===2){if(corridor[i]==='S'){
res =dfs(i +1,1);}else{
res =(dfs(i +1,0)+dfs(i +1,2))%MOD;}}else{if(corridor[i]==='S'){
res =dfs(i +1, seats +1);}else{
res =dfs(i +1, seats);}}return(dp[i][seats]= res);};returndfs(0,0);}}
publicclassSolution{privateconstint MOD =1_000_000_007;privateint[,] dp;publicintNumberOfWays(string corridor){int n = corridor.Length;
dp =newint[n,3];for(int i =0; i < n; i++){for(int j =0; j <3; j++){
dp[i, j]=-1;}}returnDfs(0,0, corridor);}privateintDfs(int i,int seats,string corridor){if(i == corridor.Length){return seats ==2?1:0;}if(dp[i, seats]!=-1){return dp[i, seats];}int res =0;if(seats ==2){if(corridor[i]=='S'){
res =Dfs(i +1,1, corridor);}else{
res =(Dfs(i +1,0, corridor)+Dfs(i +1,2, corridor))% MOD;}}else{if(corridor[i]=='S'){
res =Dfs(i +1, seats +1, corridor);}else{
res =Dfs(i +1, seats, corridor);}}return dp[i, seats]= res;}}
funcnumberOfWays(corridor string)int{
MOD :=1_000_000_007
n :=len(corridor)
dp :=make([][]int, n)for i :=range dp {
dp[i]=[]int{-1,-1,-1}}var dfs func(i, seats int)int
dfs =func(i, seats int)int{if i == n {if seats ==2{return1}return0}if dp[i][seats]!=-1{return dp[i][seats]}
res :=0if seats ==2{if corridor[i]=='S'{
res =dfs(i+1,1)}else{
res =(dfs(i+1,0)+dfs(i+1,2))% MOD
}}else{if corridor[i]=='S'{
res =dfs(i+1, seats+1)}else{
res =dfs(i+1, seats)}}
dp[i][seats]= res
return res
}returndfs(0,0)}
class Solution {privateval MOD =1_000_000_007privatelateinitvar dp: Array<IntArray>funnumberOfWays(corridor: String): Int {val n = corridor.length
dp =Array(n){IntArray(3){-1}}returndfs(0,0, corridor)}privatefundfs(i: Int, seats: Int, corridor: String): Int {if(i == corridor.length){returnif(seats ==2)1else0}if(dp[i][seats]!=-1){return dp[i][seats]}val res: Int
if(seats ==2){
res =if(corridor[i]=='S'){dfs(i +1,1, corridor)}else{(dfs(i +1,0, corridor)+dfs(i +1,2, corridor))% MOD
}}else{
res =if(corridor[i]=='S'){dfs(i +1, seats +1, corridor)}else{dfs(i +1, seats, corridor)}}
dp[i][seats]= res
return res
}}
classSolution{funcnumberOfWays(_ corridor:String)->Int{letMOD=1_000_000_007let n = corridor.count
let chars =Array(corridor)var dp =[[Int]](repeating:[-1,-1,-1], count: n)funcdfs(_ i:Int,_ seats:Int)->Int{if i == n {return seats ==2?1:0}if dp[i][seats]!=-1{return dp[i][seats]}var res =0if seats ==2{if chars[i]=="S"{
res =dfs(i +1,1)}else{
res =(dfs(i +1,0)+dfs(i +1,2))%MOD}}else{if chars[i]=="S"{
res =dfs(i +1, seats +1)}else{
res =dfs(i +1, seats)}}
dp[i][seats]= res
return res
}returndfs(0,0)}}
Time & Space Complexity
Time complexity: O(n)
Space complexity: O(n)
2. Dynamic Programming (Bottom-Up)
Intuition
We can convert the top-down approach to bottom-up by iterating from the end of the corridor to the beginning. For each position, we compute the number of ways based on whether we have 0, 1, or 2 seats in the current section.
Algorithm
Create a DP table where dp[i][seats] represents the number of ways to divide from index i onward with seats seats in the current section.
Initialize dp[n][2] = 1 (reaching the end with exactly 2 seats is one valid way).
Iterate backward through the corridor:
For each position and seat count, apply the same transitions as the top-down approach.
Return dp[0][0] (starting from index 0 with 0 seats).
classSolution:defnumberOfWays(self, corridor:str)->int:
MOD =1000000007
n =len(corridor)
dp =[[0]*3for _ inrange(n +1)]
dp[n][2]=1for i inrange(n -1,-1,-1):for seats inrange(3):if seats ==2:if corridor[i]=='S':
dp[i][seats]= dp[i +1][1]else:
dp[i][seats]=(dp[i +1][0]+ dp[i +1][2])% MOD
else:if corridor[i]=='S':
dp[i][seats]= dp[i +1][seats +1]else:
dp[i][seats]= dp[i +1][seats]return dp[0][0]
publicclassSolution{publicintnumberOfWays(String corridor){intMOD=1000000007;int n = corridor.length();int[][] dp =newint[n +1][3];
dp[n][2]=1;for(int i = n -1; i >=0; i--){for(int seats =0; seats <3; seats++){if(seats ==2){if(corridor.charAt(i)=='S'){
dp[i][seats]= dp[i +1][1];}else{
dp[i][seats]=(dp[i +1][0]+ dp[i +1][2])%MOD;}}else{if(corridor.charAt(i)=='S'){
dp[i][seats]= dp[i +1][seats +1];}else{
dp[i][seats]= dp[i +1][seats];}}}}return dp[0][0];}}
classSolution{public:intnumberOfWays(string corridor){int MOD =1000000007;int n = corridor.size();
vector<vector<int>>dp(n +1,vector<int>(3,0));
dp[n][2]=1;for(int i = n -1; i >=0; i--){for(int seats =0; seats <3; seats++){if(seats ==2){if(corridor[i]=='S'){
dp[i][seats]= dp[i +1][1];}else{
dp[i][seats]=(dp[i +1][0]+ dp[i +1][2])% MOD;}}else{if(corridor[i]=='S'){
dp[i][seats]= dp[i +1][seats +1];}else{
dp[i][seats]= dp[i +1][seats];}}}}return dp[0][0];}};
classSolution{/**
* @param {string} corridor
* @return {number}
*/numberOfWays(corridor){constMOD=1000000007;const n = corridor.length;let dp = Array.from({length: n +1},()=>Array(3).fill(0));
dp[n][2]=1;for(let i = n -1; i >=0; i--){for(let seats =0; seats <3; seats++){if(seats ===2){if(corridor[i]==='S'){
dp[i][seats]= dp[i +1][1];}else{
dp[i][seats]=(dp[i +1][0]+ dp[i +1][2])%MOD;}}else{if(corridor[i]==='S'){
dp[i][seats]= dp[i +1][seats +1];}else{
dp[i][seats]= dp[i +1][seats];}}}}return dp[0][0];}}
publicclassSolution{publicintNumberOfWays(string corridor){int MOD =1000000007;int n = corridor.Length;int[,] dp =newint[n +1,3];
dp[n,2]=1;for(int i = n -1; i >=0; i--){for(int seats =0; seats <3; seats++){if(seats ==2){if(corridor[i]=='S'){
dp[i, seats]= dp[i +1,1];}else{
dp[i, seats]=(dp[i +1,0]+ dp[i +1,2])% MOD;}}else{if(corridor[i]=='S'){
dp[i, seats]= dp[i +1, seats +1];}else{
dp[i, seats]= dp[i +1, seats];}}}}return dp[0,0];}}
funcnumberOfWays(corridor string)int{
MOD :=1000000007
n :=len(corridor)
dp :=make([][]int, n+1)for i :=range dp {
dp[i]=make([]int,3)}
dp[n][2]=1for i := n -1; i >=0; i--{for seats :=0; seats <3; seats++{if seats ==2{if corridor[i]=='S'{
dp[i][seats]= dp[i+1][1]}else{
dp[i][seats]=(dp[i+1][0]+ dp[i+1][2])% MOD
}}else{if corridor[i]=='S'{
dp[i][seats]= dp[i+1][seats+1]}else{
dp[i][seats]= dp[i+1][seats]}}}}return dp[0][0]}
class Solution {funnumberOfWays(corridor: String): Int {val MOD =1000000007val n = corridor.length
val dp =Array(n +1){IntArray(3)}
dp[n][2]=1for(i in n -1 downTo 0){for(seats in0 until 3){if(seats ==2){if(corridor[i]=='S'){
dp[i][seats]= dp[i +1][1]}else{
dp[i][seats]=(dp[i +1][0]+ dp[i +1][2])% MOD
}}else{if(corridor[i]=='S'){
dp[i][seats]= dp[i +1][seats +1]}else{
dp[i][seats]= dp[i +1][seats]}}}}return dp[0][0]}}
classSolution{funcnumberOfWays(_ corridor:String)->Int{letMOD=1000000007let n = corridor.count
let chars =Array(corridor)var dp =[[Int]](repeating:[0,0,0], count: n +1)
dp[n][2]=1for i instride(from: n -1, through:0, by:-1){for seats in0..<3{if seats ==2{if chars[i]=="S"{
dp[i][seats]= dp[i +1][1]}else{
dp[i][seats]=(dp[i +1][0]+ dp[i +1][2])%MOD}}else{if chars[i]=="S"{
dp[i][seats]= dp[i +1][seats +1]}else{
dp[i][seats]= dp[i +1][seats]}}}}return dp[0][0]}}
Time & Space Complexity
Time complexity: O(n)
Space complexity: O(n)
3. Dynamic Programming (Space Optimized)
Intuition
Since each row of the DP table only depends on the next row, we can reduce space by maintaining just a single array of size 3 (for the three possible seat counts).
Algorithm
Initialize a DP array of size 3 with dp[2] = 1.
Iterate backward through the corridor:
Create a new DP array and compute transitions based on whether the current position is a seat or plant.
Instead of DP, we can think combinatorially. First, collect all seat positions. If the count isn't even or is less than 2, there's no valid way. Otherwise, between every pair of seats (the 2nd and 3rd, 4th and 5th, etc.), we can place the divider at any position including those occupied by plants. The number of choices at each gap is the distance between consecutive pairs of seats.
Algorithm
Collect the indices of all seats in a list.
If the seat count is less than 2 or odd, return 0.
For every pair of adjacent seat groups (positions 1 and 2, positions 3 and 4, etc.), multiply res by the gap size seats[i+1] - seats[i].
classSolution:defnumberOfWays(self, corridor:str)->int:
mod =10**9+7
seats =[i for i, c inenumerate(corridor)if c =="S"]
length =len(seats)if length <2or length %2==1:return0
res =1for i inrange(1, length -1,2):
res =(res *(seats[i +1]- seats[i]))% mod
return res
publicclassSolution{publicintnumberOfWays(String corridor){int mod =1_000_000_007;List<Integer> seats =newArrayList<>();for(int i =0; i < corridor.length(); i++){if(corridor.charAt(i)=='S'){
seats.add(i);}}int length = seats.size();if(length <2|| length %2==1){return0;}long res =1;for(int i =1; i < length -1; i +=2){
res =(res *(seats.get(i +1)- seats.get(i)))% mod;}return(int) res;}}
classSolution{public:intnumberOfWays(string corridor){int mod =1'000'000'007;
vector<int> seats;for(int i =0; i < corridor.size(); i++){if(corridor[i]=='S'){
seats.push_back(i);}}int length = seats.size();if(length <2|| length %2==1){return0;}longlong res =1;for(int i =1; i < length -1; i +=2){
res =(res *(seats[i +1]- seats[i]))% mod;}return res;}};
classSolution{/**
* @param {string} corridor
* @return {number}
*/numberOfWays(corridor){const mod =1_000_000_007;const seats =[];for(let i =0; i < corridor.length; i++){if(corridor[i]==='S'){
seats.push(i);}}const length = seats.length;if(length <2|| length %2===1){return0;}let res =1;for(let i =1; i < length -1; i +=2){
res =(res *(seats[i +1]- seats[i]))% mod;}return res;}}
publicclassSolution{publicintNumberOfWays(string corridor){int mod =1_000_000_007;var seats =newList<int>();for(int i =0; i < corridor.Length; i++){if(corridor[i]=='S'){
seats.Add(i);}}int length = seats.Count;if(length <2|| length %2==1){return0;}long res =1;for(int i =1; i < length -1; i +=2){
res =(res *(seats[i +1]- seats[i]))% mod;}return(int)res;}}
funcnumberOfWays(corridor string)int{
mod :=1_000_000_007
seats :=[]int{}for i :=0; i <len(corridor); i++{if corridor[i]=='S'{
seats =append(seats, i)}}
length :=len(seats)if length <2|| length%2==1{return0}
res :=1for i :=1; i < length-1; i +=2{
res =(res *(seats[i+1]- seats[i]))% mod
}return res
}
class Solution {funnumberOfWays(corridor: String): Int {val mod =1_000_000_007val seats = mutableListOf<Int>()for(i in corridor.indices){if(corridor[i]=='S'){
seats.add(i)}}val length = seats.size
if(length <2|| length %2==1){return0}var res =1Lfor(i in1 until length -1 step 2){
res =(res *(seats[i +1]- seats[i]))% mod
}return res.toInt()}}
classSolution{funcnumberOfWays(_ corridor:String)->Int{let mod =1_000_000_007var seats =[Int]()let chars =Array(corridor)for i in0..<chars.count {if chars[i]=="S"{
seats.append(i)}}let length = seats.count
if length <2|| length %2==1{return0}var res =1for i instride(from:1, to: length -1, by:2){
res =(res *(seats[i +1]- seats[i]))% mod
}return res
}}
Time & Space Complexity
Time complexity: O(n)
Space complexity: O(n)
5. Combinatorics (Optimal)
Intuition
We can optimize the combinatorics approach by not storing all seat positions. Instead, we track the count of seats and the position of the previous seat. Whenever we complete a pair (seat count becomes even and greater than 2), we multiply by the gap between the current seat and the previous one.
Algorithm
Initialize count = 0, res = 1, and prev = -1 to track the position of the last seat.
Iterate through the corridor:
When a seat is found, increment count.
If count > 2 and count % 2 == 1 (meaning we just started a new section), multiply res by the distance from prev.
Update prev to the current position.
If count >= 2 and count % 2 == 0, return res; otherwise return 0.
classSolution:defnumberOfWays(self, corridor:str)->int:
mod =1_000_000_007
count =0
res =1
prev =-1for i, c inenumerate(corridor):if c =='S':
count +=1if count >2and count %2==1:
res =(res *(i - prev))% mod
prev = i
return res if count >=2and count %2==0else0
publicclassSolution{publicintnumberOfWays(String corridor){int mod =1_000_000_007;int count =0, res =1, prev =-1;for(int i =0; i < corridor.length(); i++){if(corridor.charAt(i)=='S'){
count++;if(count >2&& count %2==1){
res =(int)((res *(long)(i - prev))% mod);}
prev = i;}}return(count >=2&& count %2==0)? res :0;}}
classSolution{public:intnumberOfWays(string corridor){int mod =1'000'000'007, count =0, res =1, prev =-1;for(int i =0; i < corridor.size(); i++){if(corridor[i]=='S'){
count++;if(count >2&& count %2==1){
res =(1LL* res *(i - prev))% mod;}
prev = i;}}return(count >=2&& count %2==0)? res :0;}};
classSolution{/**
* @param {string} corridor
* @return {number}
*/numberOfWays(corridor){const mod =1_000_000_007;let count =0,
res =1,
prev =-1;for(let i =0; i < corridor.length; i++){if(corridor[i]==='S'){
count++;if(count >2&& count %2===1){
res =(res *(i - prev))% mod;}
prev = i;}}return count >=2&& count %2===0? res :0;}}
publicclassSolution{publicintNumberOfWays(string corridor){int mod =1_000_000_007;int count =0, prev =-1;long res =1;for(int i =0; i < corridor.Length; i++){if(corridor[i]=='S'){
count++;if(count >2&& count %2==1){
res =(res *(i - prev))% mod;}
prev = i;}}return(count >=2&& count %2==0)?(int)res :0;}}
funcnumberOfWays(corridor string)int{
mod :=1_000_000_007
count, res, prev :=0,1,-1for i :=0; i <len(corridor); i++{if corridor[i]=='S'{
count++if count >2&& count%2==1{
res =(res *(i - prev))% mod
}
prev = i
}}if count >=2&& count%2==0{return res
}return0}
class Solution {funnumberOfWays(corridor: String): Int {val mod =1_000_000_007var count =0var res =1Lvar prev =-1for(i in corridor.indices){if(corridor[i]=='S'){
count++if(count >2&& count %2==1){
res =(res *(i - prev))% mod
}
prev = i
}}returnif(count >=2&& count %2==0) res.toInt()else0}}
classSolution{funcnumberOfWays(_ corridor:String)->Int{let mod =1_000_000_007var count =0var res =1var prev =-1let chars =Array(corridor)for i in0..<chars.count {if chars[i]=="S"{
count +=1if count >2&& count %2==1{
res =(res *(i - prev))% mod
}
prev = i
}}return(count >=2&& count %2==0)? res :0}}
Time & Space Complexity
Time complexity: O(n)
Space complexity: O(1)
Common Pitfalls
Not Handling Edge Cases for Seat Count
If the total number of seats is odd or less than 2, there is no valid way to divide the corridor. Forgetting to check these conditions at the start leads to incorrect results or division by zero errors when computing gap products.
Misunderstanding Where Dividers Can Be Placed
Dividers can only be placed between sections, specifically in the gaps between the second seat of one section and the first seat of the next section. The number of valid positions for each divider equals the number of positions between consecutive seat pairs (the gap includes all plants plus the implicit space between seats).
Off-by-One Errors in Gap Calculation
The gap between the 2nd seat of one section and the 1st seat of the next is seats[i+1] - seats[i], not seats[i+1] - seats[i] - 1 or seats[i+1] - seats[i] + 1. This represents the number of possible divider positions, including placing it immediately after the 2nd seat.
Forgetting to Apply Modulo During Multiplication
The product of gaps can become extremely large. Applying modulo only at the end causes integer overflow. You must apply modulo after each multiplication step to keep the intermediate results within bounds.
Incorrect Loop Bounds in Combinatorics Approach
When iterating through seat positions to compute gap products, the loop should process pairs (seats[1], seats[2]), (seats[3], seats[4]), etc. Starting at the wrong index or using incorrect step sizes skips gaps or includes invalid pairs.