Open In App

Minimum Partition of Binary String into Powers of 5

Last Updated : 08 Jul, 2025
Summarize
Comments
Improve
Suggest changes
Share
Like Article
Like
Report

Given a binary string s, divide it into the fewest number of substrings such that:

  • Each substring represents a power of 5 in binary format.
  • No substring has leading zeros.
  • Each substring must represent a positive power of 5 (e.g., 1, 5, 25, 125, ...).

Return the minimum number of such substrings. If no valid division exists, return -1.

Examples: 

Input: str = "101101101" 
Output:
Explanation: The string "101101101" can be cut into three binary strings "101", "101", "101" each of which is a power of 5.

Input: str = "1111101" 
Output:
Explanation: The string "1111101" can be cut into one binary string "1111101" which is 125 in decimal and a power of 5.

Input: str = "00000" 
Output: -1 
Explanation: Strings of only zeroes is equivalent to 0 which is not a power of 5. 

[Naive approach] Recursive String Splitting

The idea is to recursively split the binary string into substrings that represent powers of 5 without leading zeros. At each index, we try all possible substrings starting from that position. If a substring is valid, we recursively solve for the remaining part of the string. We return the minimum number of such valid splits needed to partition the entire string.

C++
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

// function to check if a number is a power of 5
bool check(int num) {
    if (num == 0) return false;
    while (num % 5 == 0) {
        num /= 5;
    }
    return num == 1;
}

// recursive function to compute minimum cuts
int findMinCuts(int i, string &s) {
    int n = s.size();
    if (i >= n) return 0;

    int ans = n+1;
    int num = 0;

    for (int j = i; j < n; j++) {
        num = num * 2 + (s[j] == '1');
        
        // ensure there is no leading '0'
        // and the number is a power of 5
        if (s[i] != '0' && check(num)) {
            int next = findMinCuts(j + 1, s);
            if (next != n+1) {
                ans = min(ans, 1 + next);
            }
        }
    }

    return ans;
}

int cuts(string &s) {
    if (s[0] == '0') return -1;
    int n = s.size();
    int ans = findMinCuts(0, s);
    if (ans >= n+1) return -1;

    return ans;
}

int main() {
    string s = "101101101";
    int res = cuts(s);
    cout << res << endl;
    return 0;
}
Java
class GfG {

    // function to check if a number is a power of 5
    static boolean check(int num) {
        if (num == 0) return false;
        while (num % 5 == 0) {
            num /= 5;
        }
        return num == 1;
    }

    // recursive function to compute minimum cuts
    static int findMinCuts(int i, String s) {
        int n = s.length();
        if (i >= n) return 0;

        int ans = n+1;
        int num = 0;

        for (int j = i; j < n; j++) {
            num = num * 2 + (s.charAt(j) == '1' ? 1 : 0);
            
            // ensure there is no leading '0'
            // and the number is a power of 5
            if (s.charAt(i) != '0' && check(num)) {
                int next = findMinCuts(j + 1, s);
                if (next != n+1) {
                    ans = Math.min(ans, 1 + next);
                }
            }
        }

        return ans;
    }

    static int cuts(String s) {
        if (s.charAt(0) == '0') return -1;
        int n = s.length();
        int ans = findMinCuts(0, s);
        if (ans >= n+1) return -1;

        return ans;
    }

    public static void main(String[] args) {
        String s = "101101101";
        int res = cuts(s);
        System.out.println(res);
    }
}
Python
# function to check if a number is a power of 5
def check(num):
    if num == 0:
        return False
    while num % 5 == 0:
        num //= 5
    return num == 1

# recursive function to compute minimum cuts
def findMinCuts(i, s):
    n = len(s)
    if i >= n:
        return 0

    ans = n+1
    num = 0

    for j in range(i, n):
        num = num * 2 + (1 if s[j] == '1' else 0)

        # ensure there is no leading '0'
        # and the number is a power of 5
        if s[i] != '0' and check(num):
            next_cuts = findMinCuts(j + 1, s)
            if next_cuts != n+1:
                ans = min(ans, 1 + next_cuts)

    return ans

def cuts(s):
    if s[0] == '0':
        return -1
    n = len(s)
    ans = findMinCuts(0, s)
    if ans >= n+1:
        return -1

    return ans

if __name__ == "__main__":
    s = "101101101"
    res = cuts(s)
    print(res)
C#
using System;

class GfG {
    
    // function to check if a number is a power of 5
    static bool check(int num) {
        if (num == 0) return false;
        while (num % 5 == 0) {
            num /= 5;
        }
        return num == 1;
    }

    // recursive function to compute minimum cuts
    static int findMinCuts(int i, string s) {
        int n = s.Length;
        if (i >= n) return 0;

        int ans = n+1;
        int num = 0;

        for (int j = i; j < n; j++) {
            num = num * 2 + (s[j] == '1' ? 1 : 0);

            // ensure there is no leading '0'
            // and the number is a power of 5
            if (s[i] != '0' && check(num)) {
                int next = findMinCuts(j + 1, s);
                if (next != n+1) {
                    ans = Math.Min(ans, 1 + next);
                }
            }
        }

        return ans;
    }

    static int cuts(string s) {
        if (s[0] == '0') return -1;
        int n = s.Length;
        int ans = findMinCuts(0, s);
        if (ans >= n+1) return -1;

        return ans;
    }

    static void Main(string[] args) {
        string s = "101101101";
        int res = cuts(s);
        Console.WriteLine(res);
    }
}
JavaScript
// function to check if a number is a power of 5
function check(num) {
    if (num === 0) return false;
    while (num % 5 === 0) {
        num = Math.floor(num / 5);
    }
    return num === 1;
}

// recursive function to compute minimum cuts
function findMinCuts(i, s) {
    const n = s.length;
    if (i >= n) return 0;

    let ans = n+1;
    let num = 0;

    for (let j = i; j < n; j++) {
        num = num * 2 + (s[j] === '1' ? 1 : 0);

        // ensure there is no leading '0'
        // and the number is a power of 5
        if (s[i] !== '0' && check(num)) {
            let next = findMinCuts(j + 1, s);
            if (next !== n+1) {
                ans = Math.min(ans, 1 + next);
            }
        }
    }

    return ans;
}

function cuts(s) {
    if (s[0] === '0') return -1;
    const n = s.length;
    let ans = findMinCuts(0, s);
    if (ans >= n+1) return -1;

    return ans;
}

// Driver Code
let s = "101101101";
let res = cuts(s);
console.log(res);

Output
3

Time Complexity: O(2n) we try all possible partitions starting from each index, leading to an exponential number of recursive calls.
Auxiliary Space: O(n) the recursion stack can go as deep as the length of the string.

[Expected approach] Recursive String Splitting with Memoization and Precomputation

The idea is to recursively split the binary string into valid substrings that represent powers of 5 and have no leading zeros.
We define the state as memo[i] — the minimum number of cuts needed to partition the substring starting from index i.
At each index i, we try every substring s[i..j] and if it’s valid, we update: memo[i] = min(memo[i], 1 + memo[j + 1]). We use memoization (memo[] array) to store results and avoid recomputing overlapping subproblems. All valid powers of 5 are precomputed for constant-time lookup during substring validation.

C++
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <unordered_set>
using namespace std;

// recursive function to compute minimum 
// cuts with memoization
int findMinCuts(int i, string &s, vector<int> &memo, 
                            unordered_set<int> &powersOf5) {
    int n = s.size();
    if (i >= n) return 0;
    if (memo[i] != -1) return memo[i];

    int ans = n+1;
    int num = 0;

    for (int j = i; j < n; j++) {
        num = num * 2 + (s[j] == '1');

        // ensure there is no leading '0'
        // and the number is a power of 5
        if (s[i] != '0' && powersOf5.count(num)) {
            int next = findMinCuts(j + 1, s, memo, powersOf5);
            if (next != n+1) {
                ans = min(ans, 1 + next);
            }
        }
    }

    return memo[i] = ans;
}

int cuts(string &s) {
    if (s[0] == '0') return -1;
    
    // store power of 5
    unordered_set<int> powersOf5;
    int val = 1;
    while (val <= 1e9) {
        powersOf5.insert(val);
        val *= 5;
    }

    int n = s.size();
    vector<int> memo(n + 1, -1);

    int ans = findMinCuts(0, s, memo, powersOf5);
    if (ans >= n+1) return -1;

    return ans;
}

int main() {
    string s = "101101101";
    int res = cuts(s);
    cout << res << endl;
    return 0;
}
Java
import java.util.Set;
import java.util.HashSet;
import java.util.Arrays;

class GfG {

    // recursive function to compute minimum cuts with memoization
    static int findMinCuts(int i, String s, int[] memo, 
                        Set<Integer> powersOf5) {
        int n = s.length();
        if (i >= n) return 0;
        if (memo[i] != -1) return memo[i];

        int ans = n + 1;
        int num = 0;

        for (int j = i; j < n; j++) {
            num = num * 2 + (s.charAt(j) == '1' ? 1 : 0);

            // ensure there is no leading '0'
            // and the number is a power of 5
            if (s.charAt(i) != '0' && powersOf5.contains(num)) {
                int next = findMinCuts(j + 1, s, memo, powersOf5);
                if (next != n + 1) {
                    ans = Math.min(ans, 1 + next);
                }
            }
        }

        return memo[i] = ans;
    }

    static int cuts(String s) {
        if (s.charAt(0) == '0') return -1;

        // store power of 5 
        Set<Integer> powersOf5 = new HashSet<>();
        int val = 1;
        while (val <= 1_000_000_000) {
            powersOf5.add(val);
            val *= 5;
        }

        int n = s.length();
        int[] memo = new int[n + 1];
        Arrays.fill(memo, -1);

        int ans = findMinCuts(0, s, memo, powersOf5);
        return (ans >= n + 1) ? -1 : ans;
    }

    public static void main(String[] args) {
        String s = "101101101";
        int res = cuts(s);
        System.out.println(res);
    }
}
Python
# recursive function to compute minimum cuts with memoization
def findMinCuts(i, s, memo, powersOf5):
    n = len(s)
    if i >= n:
        return 0
    if memo[i] != -1:
        return memo[i]

    ans = n+1
    num = 0

    for j in range(i, n):
        num = num * 2 + (1 if s[j] == '1' else 0)

        # ensure there is no leading '0'
        # and the number is a power of 5
        if s[i] != '0' and num in powersOf5:
            next_cut = findMinCuts(j + 1, s, memo, powersOf5)
            if next_cut != n+1:
                ans = min(ans, 1 + next_cut)

    memo[i] = ans
    return ans

def cuts(s):
    if s[0] == '0':
        return -1

    # store power of 5
    powersOf5 = set()
    val = 1
    while val <= 10**9:
        powersOf5.add(val)
        val *= 5
        
        
    n = len(s)
    memo = [-1] * (n + 1)

    ans = findMinCuts(0, s, memo, powersOf5)
    return -1 if ans >= n+1 else ans

if __name__ == "__main__":
    s = "101101101"
    res = cuts(s)
    print(res)
C#
using System;
using System.Collections.Generic;

class GfG {
    // recursive function to compute minimum 
    // cuts with memoization
    static int findMinCuts(int i, string s, int[] memo, 
                                HashSet<int> powersOf5) {
        int n = s.Length;
        if (i >= n) return 0;
        if (memo[i] != -1) return memo[i];

        int ans = n+1;
        int num = 0;

        for (int j = i; j < n; j++) {
            num = num * 2 + (s[j] == '1' ? 1 : 0);

            // ensure there is no leading '0'
            // and the number is a power of 5
            if (s[i] != '0' && powersOf5.Contains(num)) {
                int next = findMinCuts(j + 1, s, memo, powersOf5);
                if (next != n+1) {
                    ans = Math.Min(ans, 1 + next);
                }
            }
        }

        return memo[i] = ans;
    }

    static int cuts(string s) {
        if (s[0] == '0') return -1;

        // store power of 5
        HashSet<int> powersOf5 = new HashSet<int>();
        int val = 1;
        while (val <= 1000000000) {
            powersOf5.Add(val);
            val *= 5;
        }

        int n = s.Length;
        int[] memo = new int[n + 1];
        Array.Fill(memo, -1);

        int ans = findMinCuts(0, s, memo, powersOf5);
        return (ans >= n+1) ? -1 : ans;
    }

    static void Main(string[] args) {
        string s = "101101101";
        int res = cuts(s);
        Console.WriteLine(res);
    }
}
JavaScript
// recursive function to compute minimum 
// cuts with memoization
function findMinCuts(i, s, memo, powersOf5) {
    const n = s.length;
    if (i >= n) return 0;
    if (memo[i] !== -1) return memo[i];

    let ans = n+1;
    let num = 0;

    for (let j = i; j < n; j++) {
        num = num * 2 + (s[j] === '1' ? 1 : 0);

        // ensure there is no leading '0'
        // and the number is a power of 5
        if (s[i] !== '0' && powersOf5.has(num)) {
            const next = findMinCuts(j + 1, s, memo, powersOf5);
            if (next !== n+1) {
                ans = Math.min(ans, 1 + next);
            }
        }
    }

    memo[i] = ans;
    return ans;
}

function cuts(s) {
    if (s[0] === '0') return -1;

    // store power of 5
    const powersOf5 = new Set();
    let val = 1;
    while (val <= 1e9) {
        powersOf5.add(val);
        val *= 5;
    }

    const n = s.length;
    const memo = new Array(n + 1).fill(-1);

    const ans = findMinCuts(0, s, memo, powersOf5);
    return ans >= n+1 ? -1 : ans;
}

// Driver Code
const s = "101101101";
const res = cuts(s);
console.log(res);

Output
3

Time Complexity: O(n²) for each of the n starting indices, we try up to n substrings. Each substring is validated in constant time due to the precomputed powerOf5 set.
Auxiliary Space: O(n) we use a memo array of size n for memoization. The precomputed powers of 5 set uses constant space (O(1)) .

[Efficient approach] Bottom-Up Dynamic Programming with Precomputed Valid Substrings

The idea is to use bottom-up dynamic programming (tabulation) to find the minimum number of cuts to partition a binary string into valid substrings.
A substring is valid if it represents a power of 5 in binary and has no leading zeros.
We iterate from right to left and build up the solution using previously computed results.

State: dp[i] represent the minimum number of cuts needed to partition the suffix s[i..n-1] into valid power of 5 binary substrings.

Transition: At each position i, we try every substring s[i..j] where:

  • s[i] != '0' (to avoid leading zeros)
  • s[i..j] is a valid binary representation of a power of 5 (checked via precomputed set)
  • if both conditions hold: dp[i] = min(dp[i], 1 + dp[j+1])
C++
#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
#include <algorithm>
using namespace std;

int cuts(string &s) {
    

    if (s[0] == '0') return -1;
    int n = s.size();

    const int maxi = n+1;
    unordered_set<int> powersOf5;

    // store power of 5
    int val = 1;
    while (val <= 1e9) {
        powersOf5.insert(val);
        val *= 5;
    }
    
    vector<int> dp(n + 1, maxi);
    
    // base case empty suffix requires 0 cuts
    dp[n] = 0; 

    for (int i = n - 1; i >= 0; --i) {
        
        // ensure there is no leading '0'
        if(s[i] == '0') continue;
        
        int num = 0;
        for (int j = i; j < n; ++j) {
            num = num * 2 + (s[j] == '1');

            // and the number is a power of 5
            if (powersOf5.count(num)) {
                if (dp[j + 1] != maxi) {
                    dp[i] = min(dp[i], 1 + dp[j + 1]);
                }
            }
        }
    }

    return dp[0] >= maxi ? -1 : dp[0];
}

int main() {
    string s = "101101101";
    int res = cuts(s);
    cout << res << endl;
    return 0;
}
Java
import java.util.Set;
import java.util.HashSet;
import java.util.Arrays;

class GfG {

    public static int cuts(String s) {
        if (s.charAt(0) == '0') return -1;
        
        int n = s.length();
        int maxi = n+1;
        Set<Integer> powersOf5 = new HashSet<>();

        // store power of 5
        int val = 1;
        while (val <= 1_000_000_000) {
            powersOf5.add(val);
            val *= 5;
        }

        
        int[] dp = new int[n + 1];
        Arrays.fill(dp, maxi);

        // base case empty suffix requires 0 cuts
        dp[n] = 0;

        for (int i = n - 1; i >= 0; --i) {

            // ensure there is no leading '0'
            if (s.charAt(i) == '0') continue;

            int num = 0;
            for (int j = i; j < n; ++j) {
                num = num * 2 + (s.charAt(j) == '1' ? 1 : 0);

                // and the number is a power of 5
                if (powersOf5.contains(num)) {
                    if (dp[j + 1] != maxi) {
                        dp[i] = Math.min(dp[i], 1 + dp[j + 1]);
                    }
                }
            }
        }

        return dp[0] >= maxi ? -1 : dp[0];
    }

    public static void main(String[] args) {
        String s = "101101101";
        int res = cuts(s);
        System.out.println(res);
    }
}
Python
def cuts(s):
    if s[0] == '0':
        return -1
        
    n = len(s)
    maxi = n+1
    powersOf5 = set()

    # store power of 5
    val = 1
    while val <= 1e9:
        powersOf5.add(val)
        val *= 5

    
    dp = [maxi] * (n + 1)

    # base case empty suffix requires 0 cuts
    dp[n] = 0

    for i in range(n - 1, -1, -1):

        # ensure there is no leading '0'
        if s[i] == '0':
            continue

        num = 0
        for j in range(i, n):
            num = num * 2 + (1 if s[j] == '1' else 0)

            # and the number is a power of 5
            if num in powersOf5:
                if dp[j + 1] != maxi:
                    dp[i] = min(dp[i], 1 + dp[j + 1])

    return -1 if dp[0] >= maxi else dp[0]


if __name__ == "__main__":
    s = "101101101"
    res = cuts(s)
    print(res)
C#
using System;
using System.Collections.Generic;

class GfG {

    public static int cuts(string s) {
        
        if (s[0] == '0') return -1;
        int n = s.Length;
        int maxi = n+1;
        HashSet<int> powersOf5 = new HashSet<int>();

        // store power of 5
        int val = 1;
        while (val <= 1000000000) {
            powersOf5.Add(val);
            val *= 5;
        }

        
        int[] dp = new int[n + 1];
        Array.Fill(dp, maxi);

        // base case empty suffix requires 0 cuts
        dp[n] = 0;

        for (int i = n - 1; i >= 0; --i) {

            // ensure there is no leading '0'
            if (s[i] == '0') continue;

            int num = 0;
            for (int j = i; j < n; ++j) {
                num = num * 2 + (s[j] == '1' ? 1 : 0);

                // and the number is a power of 5
                if (powersOf5.Contains(num)) {
                    if (dp[j + 1] != maxi) {
                        dp[i] = Math.Min(dp[i], 1 + dp[j + 1]);
                    }
                }
            }
        }

        return dp[0] >= maxi ? -1 : dp[0];
    }

    static void Main(string[] args) {
        string s = "101101101";
        int res = cuts(s);
        Console.WriteLine(res);
    }
}
JavaScript
function cuts(s) {
    if (s[0] === '0') return -1;
    
    const n = s.length;
    const maxi = n+1;
    const powersOf5 = new Set();

    // store power of 5
    let val = 1;
    while (val <= 1e9) {
        powersOf5.add(val);
        val *= 5;
    }

    
    const dp = new Array(n + 1).fill(maxi);

    // base case empty suffix requires 0 cuts
    dp[n] = 0;

    for (let i = n - 1; i >= 0; i--) {

        // ensure there is no leading '0'
        if (s[i] === '0') continue;

        let num = 0;
        for (let j = i; j < n; j++) {
            num = num * 2 + (s[j] === '1' ? 1 : 0);

            // and the number is a power of 5
            if (powersOf5.has(num)) {
                if (dp[j + 1] !== maxi) {
                    dp[i] = Math.min(dp[i], 1 + dp[j + 1]);
                }
            }
        }
    }

    return dp[0] >= maxi ? -1 : dp[0];
}

// Driver Code
const s = "101101101";
const res = cuts(s);
console.log(res);

Output
3

Time Complexity: O(n²) for each index i from n-1 to 0, we try every substring s[i..j] (at most n substrings). Each substring is checked in constant time using a precomputed set of powers of 5.
Auxiliary space: O(n) an array dp[] of size n+1 is used to store minimum cuts. The powewOf5 set uses O(1) space.
 


Similar Reads