Splitting a String Into Descending Consecutive Values
MediumUpdated: Aug 2, 2025
Practice on:
Problem
You are given a string s that consists of only digits.
Check if we can split s into two or more non-empty substrings such that the numerical values of the substrings are in descending order and the difference between numerical values of every two adjacent substrings is equal to 1.
- For example, the string
s = "0090089"can be split into["0090", "089"]with numerical values[90,89]. The values are in descending order and adjacent values differ by1, so this way is valid. - Another example, the string
s = "001"can be split into["0", "01"],["00", "1"], or["0", "0", "1"]. However all the ways are invalid because they have numerical values[0,1],[0,1], and[0,0,1]respectively, all of which are not in descending order.
Return true if it is possible to split s as described above_, or_ false otherwise.
A substring is a contiguous sequence of characters in a string.
Examples
Example 1
Input: s = "1234"
Output: false
Explanation: There is no valid way to split s.
Example 2
Input: s = "050043"
Output: true
Explanation: s can be split into ["05", "004", "3"] with numerical values [5,4,3].
The values are in descending order with adjacent values differing by 1.
Example 3
Input: s = "9080701"
Output: false
Explanation: There is no valid way to split s.
Solution
Method 1 - Backtracking with Pruning
Intuition
We want to split the string into two or more substrings such that their numerical values form a strictly descending sequence with each adjacent difference equal to 1. Backtracking allows us to try all possible splits, pruning paths that cannot possibly satisfy the condition.
Approach
- Start from the first character and try every possible split for the first number.
- For each split, recursively try to split the rest of the string such that each next number is exactly 1 less than the previous.
- Track the previous number and the count of splits. If we reach the end of the string and have at least two numbers, return true.
- Prune paths early if the difference is not 1.
Complexity
- ⏰ Time complexity:
O(n^2)— For each starting index, we try all possible splits, and each recursive call advances the index. - 🧺 Space complexity:
O(n)— The recursion stack can go up to the length of the string.
Code
C++
class Solution {
public:
bool splitString(string s) {
return backtrack(s, 0, -1, 0);
}
private:
bool backtrack(const string& s, int idx, long long prev, int count) {
if (idx == s.size()) return count >= 2;
long long curr = 0;
for (int i = idx; i < s.size(); ++i) {
curr = curr * 10 + (s[i] - '0');
if (prev == -1 || prev - curr == 1) {
if (backtrack(s, i + 1, curr, count + 1)) return true;
}
}
return false;
}
};
Go
type Solution struct{}
func splitString(s string) bool {
var backtrack func(idx int, prev int64, count int) bool
backtrack = func(idx int, prev int64, count int) bool {
if idx == len(s) {
return count >= 2
}
var curr int64 = 0
for i := idx; i < len(s); i++ {
curr = curr*10 + int64(s[i]-'0')
if prev == -1 || prev-curr == 1 {
if backtrack(i+1, curr, count+1) {
return true
}
}
}
return false
}
return backtrack(0, -1, 0)
}
Java
class Solution {
public boolean splitString(String s) {
return backtrack(s, 0, -1, 0);
}
private boolean backtrack(String s, int idx, long prev, int count) {
if (idx == s.length()) return count >= 2;
long curr = 0;
for (int i = idx; i < s.length(); i++) {
curr = curr * 10 + (s.charAt(i) - '0');
if (prev == -1 || prev - curr == 1) {
if (backtrack(s, i + 1, curr, count + 1)) return true;
}
}
return false;
}
}
Kotlin
class Solution {
fun splitString(s: String): Boolean {
fun backtrack(idx: Int, prev: Long, count: Int): Boolean {
if (idx == s.length) return count >= 2
var curr = 0L
for (i in idx until s.length) {
curr = curr * 10 + (s[i] - '0')
if (prev == -1L || prev - curr == 1L) {
if (backtrack(i + 1, curr, count + 1)) return true
}
}
return false
}
return backtrack(0, -1L, 0)
}
}
Python
class Solution:
def splitString(self, s: str) -> bool:
def backtrack(idx: int, prev: int, count: int) -> bool:
if idx == len(s):
return count >= 2
curr = 0
for i in range(idx, len(s)):
curr = curr * 10 + int(s[i])
if prev == -1 or prev - curr == 1:
if backtrack(i + 1, curr, count + 1):
return True
return False
return backtrack(0, -1, 0)
Rust
impl Solution {
pub fn split_string(s: String) -> bool {
fn backtrack(s: &str, idx: usize, prev: i64, count: usize) -> bool {
if idx == s.len() {
return count >= 2;
}
let mut curr: i64 = 0;
for i in idx..s.len() {
curr = curr * 10 + (s.as_bytes()[i] - b'0') as i64;
if prev == -1 || prev - curr == 1 {
if backtrack(s, i + 1, curr, count + 1) {
return true;
}
}
}
false
}
backtrack(&s, 0, -1, 0)
}
}
TypeScript
class Solution {
splitString(s: string): boolean {
function backtrack(idx: number, prev: number, count: number): boolean {
if (idx === s.length) return count >= 2;
let curr = 0;
for (let i = idx; i < s.length; i++) {
curr = curr * 10 + Number(s[i]);
if (prev === -1 || prev - curr === 1) {
if (backtrack(i + 1, curr, count + 1)) return true;
}
}
return false;
}
return backtrack(0, -1, 0);
}
}