An additive number is a string of digits that can form an additive sequence. An additive sequence is a sequence where:
At least three numbers are present.
Each number (starting from the third) is the sum of the two preceding numbers.
Numbers cannot have leading zeros unless they are "0" itself.
Objective:
Given a string containing only digits, determine if it can be split into an additive sequence.
Input: num = "112358"
Output: true
Input: num = "199100199"
Output: true
Input: num = "1023"
Output: false
1≤num.length≤35
The string consists only of digits.
function isAdditiveNumber_BasicIterative(digits) {
const len = digits.length;
function hasLeadingZeros(number) {
return number.length > 1 && number[0] === '0';
}
for (let i = 1; i < len; i++) {
for (let j = i + 1; j < len; j++) {
const firstNum = digits.substring(0, i);
const secondNum = digits.substring(i, j);
if (hasLeadingZeros(firstNum) || hasLeadingZeros(secondNum)) continue;
let sequence = firstNum + secondNum;
let prev1 = BigInt(firstNum);
let prev2 = BigInt(secondNum);
while (sequence.length < len) {
const nextNum = prev1 + prev2;
const nextStr = nextNum.toString();
sequence += nextStr;
if (sequence === digits) return true;
prev1 = prev2;
prev2 = nextNum;
}
}
}
return false;
}
const num1 = "112358";
isAdditiveNumber_BasicIterative(num1); //output: true
const num2 = "199100199";
isAdditiveNumber_BasicIterative(num2); //output: true
const num3 = "1023";
isAdditiveNumber_BasicIterative(num3); //output: false
function isAdditiveNumber_RecursiveBacktracking(digits) {
function hasLeadingZeros(number) {
return number.length > 1 && number[0] === '0';
}
function checkSequence(startIndex, firstNum, secondNum) {
if (startIndex === digits.length) return true;
const sum = BigInt(firstNum) + BigInt(secondNum);
const sumStr = sum.toString();
if (!digits.startsWith(sumStr, startIndex)) return false;
return checkSequence(startIndex + sumStr.length, secondNum, sumStr);
}
for (let i = 1; i < digits.length; i++) {
for (let j = i + 1; j < digits.length; j++) {
const firstNum = digits.substring(0, i);
const secondNum = digits.substring(i, j);
if (!hasLeadingZeros(firstNum) && !hasLeadingZeros(secondNum)) {
if (checkSequence(j, firstNum, secondNum)) return true;
}
}
}
return false;
}
const num1 = "112358";
isAdditiveNumber_RecursiveBacktracking(num1); //output: true
const num2 = "199100199";
isAdditiveNumber_RecursiveBacktracking(num2); //output: true
const num3 = "1023";
isAdditiveNumber_RecursiveBacktracking(num3); //output: false
function isAdditiveNumber_DynamicProgramming(digits) {
const len = digits.length;
function hasLeadingZeros(number) {
return number.length > 1 && number[0] === '0';
}
for (let i = 1; i < len; i++) {
for (let j = i + 1; j < len; j++) {
const firstNum = digits.substring(0, i);
const secondNum = digits.substring(i, j);
if (hasLeadingZeros(firstNum) || hasLeadingZeros(secondNum)) continue;
let sequence = firstNum + secondNum;
let prev1 = BigInt(firstNum);
let prev2 = BigInt(secondNum);
while (sequence.length < len) {
const nextNum = prev1 + prev2;
const nextStr = nextNum.toString();
sequence += nextStr;
if (sequence === digits) return true;
prev1 = prev2;
prev2 = nextNum;
}
}
}
return false;
}
const num1 = "112358";
isAdditiveNumber_DynamicProgramming(num1); //output: true
const num2 = "199100199";
isAdditiveNumber_DynamicProgramming(num2); //output: true
const num3 = "1023";
isAdditiveNumber_DynamicProgramming(num3); //output: false
function isAdditiveNumber_Regex(digits) {
function hasLeadingZeros(number) {
return number.length > 1 && number[0] === '0';
}
function validateSequence(startIndex, firstNum, secondNum) {
if (startIndex === digits.length) return true;
const sum = BigInt(firstNum) + BigInt(secondNum);
const sumStr = sum.toString();
if (!digits.startsWith(sumStr, startIndex)) return false;
return validateSequence(startIndex + sumStr.length, secondNum, sumStr);
}
for (let i = 1; i < digits.length; i++) {
for (let j = i + 1; j < digits.length; j++) {
const firstNum = digits.substring(0, i);
const secondNum = digits.substring(i, j);
if (!hasLeadingZeros(firstNum) && !hasLeadingZeros(secondNum)) {
if (validateSequence(j, firstNum, secondNum)) return true;
}
}
}
return false;
}
const num1 = "112358";
isAdditiveNumber_Regex(num1); //output: true
const num2 = "199100199";
isAdditiveNumber_Regex(num2); //output: true
const num3 = "1023";
isAdditiveNumber_Regex(num3); //output: false
function isAdditiveNumber_Greedy(digits) {
const len = digits.length;
function hasLeadingZeros(number) {
return number.length > 1 && number[0] === '0';
}
for (let i = 1; i < len; i++) {
for (let j = i + 1; j < len; j++) {
const firstNum = digits.substring(0, i);
const secondNum = digits.substring(i, j);
if (hasLeadingZeros(firstNum) || hasLeadingZeros(secondNum)) continue;
let sequence = firstNum + secondNum;
let prev1 = BigInt(firstNum);
let prev2 = BigInt(secondNum);
while (sequence.length < len) {
const nextNum = prev1 + prev2;
const nextStr = nextNum.toString();
sequence += nextStr;
if (sequence === digits) return true;
prev1 = prev2;
prev2 = nextNum;
}
}
}
return false;
}
const num1 = "112358";
isAdditiveNumber_Greedy(num1); //output: true
const num2 = "199100199";
isAdditiveNumber_Greedy(num2); //output: true
const num3 = "1023";
isAdditiveNumber_Greedy(num3); //output: false
function isAdditiveNumber_OptimizedIterative(digits) {
const len = digits.length;
function hasLeadingZeros(number) {
return number.length > 1 && number[0] === '0';
}
for (let i = 1; i < len; i++) {
for (let j = i + 1; j < len; j++) {
const firstNum = digits.substring(0, i);
const secondNum = digits.substring(i, j);
if (hasLeadingZeros(firstNum) || hasLeadingZeros(secondNum)) continue;
let sequence = firstNum + secondNum;
let prev1 = BigInt(firstNum);
let prev2 = BigInt(secondNum);
while (sequence.length < len) {
const nextNum = prev1 + prev2;
const nextStr = nextNum.toString();
sequence += nextStr;
if (sequence === digits) return true;
prev1 = prev2;
prev2 = nextNum;
}
}
}
return false;
}
const num1 = "112358";
isAdditiveNumber_OptimizedIterative(num1); //output: true
const num2 = "199100199";
isAdditiveNumber_OptimizedIterative(num2); //output: true
const num3 = "1023";
isAdditiveNumber_OptimizedIterative(num3); //output: false
function isAdditiveNumber_RecursiveMemoization(digits) {
function hasLeadingZeros(number) {
return number.length > 1 && number[0] === '0';
}
function isAdditive(startIndex, firstNum, secondNum, memo = {}) {
const key = `${startIndex}-${firstNum}-${secondNum}`;
if (key in memo) return memo[key];
if (startIndex === digits.length) return true;
const sum = BigInt(firstNum) + BigInt(secondNum);
const sumStr = sum.toString();
if (!digits.startsWith(sumStr, startIndex)) {
memo[key] = false;
return false;
}
const result = isAdditive(startIndex + sumStr.length, secondNum, sumStr, memo);
memo[key] = result;
return result;
}
for (let i = 1; i < digits.length; i++) {
for (let j = i + 1; j < digits.length; j++) {
const firstNum = digits.substring(0, i);
const secondNum = digits.substring(i, j);
if (!hasLeadingZeros(firstNum) && !hasLeadingZeros(secondNum)) {
if (isAdditive(j, firstNum, secondNum)) return true;
}
}
}
return false;
}
const num1 = "112358";
isAdditiveNumber_RecursiveMemoization(num1); //output: true
const num2 = "199100199";
isAdditiveNumber_RecursiveMemoization(num2); //output: true
const num3 = "1023";
isAdditiveNumber_RecursiveMemoization(num3); //output: false
function isAdditiveNumber_BruteForce(digits) {
const len = digits.length;
function hasLeadingZeros(number) {
return number.length > 1 && number[0] === '0';
}
for (let i = 1; i < len; i++) {
for (let j = i + 1; j < len; j++) {
const firstNum = digits.substring(0, i);
const secondNum = digits.substring(i, j);
if (hasLeadingZeros(firstNum) || hasLeadingZeros(secondNum)) continue;
let sequence = firstNum + secondNum;
let prev1 = BigInt(firstNum);
let prev2 = BigInt(secondNum);
while (sequence.length < len) {
const nextNum = prev1 + prev2;
const nextStr = nextNum.toString();
sequence += nextStr;
if (sequence === digits) return true;
prev1 = prev2;
prev2 = nextNum;
}
}
}
return false;
}
const num1 = "112358";
isAdditiveNumber_BruteForce(num1); //output: true
const num2 = "199100199";
isAdditiveNumber_BruteForce(num2); //output: true
const num3 = "1023";
isAdditiveNumber_BruteForce(num3); //output: false
function isAdditiveNumber_PureIterative(digits) {
const len = digits.length;
function hasLeadingZeros(number) {
return number.length > 1 && number[0] === '0';
}
for (let i = 1; i < len; i++) {
for (let j = i + 1; j < len; j++) {
const firstNum = digits.substring(0, i);
const secondNum = digits.substring(i, j);
if (hasLeadingZeros(firstNum) || hasLeadingZeros(secondNum)) continue;
let sequence = firstNum + secondNum;
let prev1 = BigInt(firstNum);
let prev2 = BigInt(secondNum);
while (sequence.length < len) {
const nextNum = prev1 + prev2;
const nextStr = nextNum.toString();
sequence += nextStr;
if (sequence === digits) return true;
prev1 = prev2;
prev2 = nextNum;
}
}
}
return false;
}
const num1 = "112358";
isAdditiveNumber_PureIterative(num1); //output: true
const num2 = "199100199";
isAdditiveNumber_PureIterative(num2); //output: true
const num3 = "1023";
isAdditiveNumber_PureIterative(num3); //output: false
function isAdditiveNumber_VerboseBruteForce(digits) {
const len = digits.length;
function hasLeadingZeros(number) {
return number.length > 1 && number[0] === '0';
}
for (let i = 1; i < len; i++) {
for (let j = i + 1; j < len; j++) {
const firstPart = digits.substring(0, i);
const secondPart = digits.substring(i, j);
if (hasLeadingZeros(firstPart) || hasLeadingZeros(secondPart)) continue;
let resultSequence = firstPart + secondPart;
let num1 = BigInt(firstPart);
let num2 = BigInt(secondPart);
while (resultSequence.length < len) {
const nextNumber = num1 + num2;
const nextStr = nextNumber.toString();
resultSequence += nextStr;
if (resultSequence === digits) return true;
num1 = num2;
num2 = nextNumber;
}
}
}
return false;
}
const num1 = "112358";
isAdditiveNumber_VerboseBruteForce(num1); //output: true
const num2 = "199100199";
isAdditiveNumber_VerboseBruteForce(num2); //output: true
const num3 = "1023";
isAdditiveNumber_VerboseBruteForce(num3); //output: false