Additive Number
MEDIUMDescription
An additive number is a string whose digits can form an additive sequence.
A valid additive sequence should contain at least three numbers. Except for the first two numbers, each subsequent number in the sequence must be the sum of the preceding two.
Given a string containing only digits, return true if it is an additive number or false otherwise.
Note: Numbers in the additive sequence cannot have leading zeros, so sequence 1, 2, 03 or 1, 02, 3 is invalid.
Example 1:
Input: "112358" Output: true Explanation: The digits can form an additive sequence: 1, 1, 2, 3, 5, 8. 1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8
Example 2:
Input: "199100199" Output: true Explanation: The additive sequence is: 1, 99, 100, 199. 1 + 99 = 100, 99 + 100 = 199
Constraints:
1 <= num.length <= 35numconsists only of digits.
Follow up: How would you handle overflow for very large input integers?
Approaches
Checkout 2 different approaches to solve Additive Number. Click on different approaches to view the approach and algorithm in detail.
Backtracking Search for First Two Numbers
A much more efficient approach is to realize that an additive sequence is uniquely determined by its first two numbers. We can iterate through all possible first and second numbers, and for each pair, check if they can form a valid additive sequence that consumes the entire input string.
Algorithm
-
- The main function
isAdditiveNumberiterates through all possible lengths,iandj, for the first two numbers.
- The main function
-
- The loop for
i(length of the first number) runs from1ton/2.
- The loop for
-
- The loop for
j(length of the second number) runs from1up to the point where the remaining string lengthn-i-jis at leastmax(i, j).
- The loop for
-
- Inside the loops, extract the first two number strings,
s1ands2.
- Inside the loops, extract the first two number strings,
-
- Check for invalid leading zeros. If
s1has a leading zero (and length > 1), we can break the outer loop. Ifs2has one, continue to the nextj.
- Check for invalid leading zeros. If
-
- Call a recursive helper function,
checkSequence(s1, s2, rest_of_string), to validate the remainder of the string.
- Call a recursive helper function,
-
- The
checkSequencefunction is the core of the backtracking:
- a. Base Case: If the remaining string is empty, it means the whole string was consumed by a valid sequence, so return
true. - b. Calculate the sum of the two previous numbers using a
stringAddhelper. - c. Check if the remaining string starts with the calculated sum string. If not, return
false. - d. If it does, make a recursive call with the next set of numbers:
checkSequence(s2, sum, rest.substring(sum.length())).
- The
-
- If
checkSequencereturnstrueat any point, the main function returnstrue.
- If
-
- If the loops complete without finding a solution, return
false.
- If the loops complete without finding a solution, return
We use two nested loops to select the first two numbers, num1 and num2. The outer loop determines the length of num1, and the inner loop determines the length of num2. Some optimizations can be applied to the loop bounds. For instance, the length of the first or second number cannot be more than half the total string length, because the third number must be at least as long as the longer of the first two.
After selecting num1 and num2, we start a validation process. This process recursively or iteratively generates the next number in the sequence (sum = num1 + num2) and checks if the remaining input string starts with this sum. If it does, we continue the process with num2 and sum. If at any point the check fails, or if we successfully consume the entire string, the process terminates.
Since the numbers can be very large (up to 35 digits), we cannot use standard integer types like long. Instead, we must represent numbers as strings and implement a string addition helper function to handle the 'Follow up' part of the problem.
class Solution {
public boolean isAdditiveNumber(String num) {
int n = num.length();
if (n < 3) return false;
// i is the length of the first number
for (int i = 1; i <= n / 2; ++i) {
// j is the length of the second number
// The third number's length must be >= max(i, j).
// So, n - i - j >= max(i, j).
for (int j = 1; Math.max(i, j) <= n - i - j; ++j) {
if (isValid(i, j, num)) {
return true;
}
}
}
return false;
}
// Checks if a valid sequence can be formed starting with numbers of length i and j
private boolean isValid(int i, int j, String num) {
String s1 = num.substring(0, i);
String s2 = num.substring(i, i + j);
// Rule: no leading zeros, unless the number is "0" itself.
if (s1.length() > 1 && s1.charAt(0) == '0') return false;
if (s2.length() > 1 && s2.charAt(0) == '0') return false;
String rest = num.substring(i + j);
return checkSequence(s1, s2, rest);
}
// Recursively checks if the 'rest' of the string follows the additive sequence
private boolean checkSequence(String prev1, String prev2, String rest) {
if (rest.isEmpty()) {
return true; // The entire string has been consumed by the sequence
}
String sum = stringAdd(prev1, prev2);
if (!rest.startsWith(sum)) {
return false; // The next number in the string doesn't match the sum
}
// Recurse with the next pair of numbers
return checkSequence(prev2, sum, rest.substring(sum.length()));
}
// Helper function to add two numbers represented as strings
private String stringAdd(String n1, String n2) {
StringBuilder res = new StringBuilder();
int i = n1.length() - 1;
int j = n2.length() - 1;
int carry = 0;
while (i >= 0 || j >= 0 || carry != 0) {
int digit1 = i >= 0 ? n1.charAt(i--) - '0' : 0;
int digit2 = j >= 0 ? n2.charAt(j--) - '0' : 0;
int sum = digit1 + digit2 + carry;
res.append(sum % 10);
carry = sum / 10;
}
return res.reverse().toString();
}
}
Complexity Analysis
Pros and Cons
- Significantly more efficient than brute-forcing all partitions.
- Passes within the time limits for the given constraints.
- The logic is a direct and structured way to search for the solution.
- The complexity is polynomial, which might be slow for very large
n(thoughn=35is fine). - Requires careful implementation of string addition and handling of edge cases like leading zeros.
Code Solutions
Checking out 3 solutions in different languages for Additive Number. Click on different languages to view the code.
class Solution { public boolean isAdditiveNumber ( String num ) { int n = num . length (); for ( int i = 1 ; i < Math . min ( n - 1 , 19 ); ++ i ) { for ( int j = i + 1 ; j < Math . min ( n , i + 19 ); ++ j ) { if ( i > 1 && num . charAt ( 0 ) == '0' ) { break ; } if ( j - i > 1 && num . charAt ( i ) == '0' ) { continue ; } long a = Long . parseLong ( num . substring ( 0 , i )); long b = Long . parseLong ( num . substring ( i , j )); if ( dfs ( a , b , num . substring ( j ))) { return true ; } } } return false ; } private boolean dfs ( long a , long b , String num ) { if ( "" . equals ( num )) { return true ; } if ( a + b > 0 && num . charAt ( 0 ) == '0' ) { return false ; } for ( int i = 1 ; i < Math . min ( num . length () + 1 , 19 ); ++ i ) { if ( a + b == Long . parseLong ( num . substring ( 0 , i ))) { if ( dfs ( b , a + b , num . substring ( i ))) { return true ; } } } return false ; } }Video Solution
Watch the video walkthrough for Additive Number
Similar Questions
5 related questions you might find useful
Patterns:
Data Structures:
Companies:
Subscribe to Scale Engineer newsletter
Learn about System Design, Software Engineering, and interview experiences every week.
No spam, unsubscribe at any time.