Given a string, the task is to find whether it contains an additive sequence or not. A string contains an additive sequence if its digits can make a sequence of numbers in which every number is addition of previous two numbers. A valid string should contain at least three digit to make one additive sequence.Ā
Examples:Ā
Input : s = ā235813ā
Output : true
Explanation: 2 + 3 = 5, 3 + 5 = 8, 5 + 8 = 13Input : s = ā199100199ā
Output : true
Explanation: 1 + 99 = 100, 99 + 100 = 199Input : s = ā12345678ā
Output : false
Table of Content
[Naive Approach] Recursion + String Addition ā O(n³) Time and O(n) Space
The idea is to try all possible ways to split the string into the first two numbers, then check if the string after the two is sum of the two and recursively verify whether the rest of the string follows the additive sequence property.
- Run two nested loops for i and j to try all possible combinations of first two strings of lengths i and j respectively.
- Check if sum of substring from 0 to i-1 and i to i+j-1 is present at the index starting from i+j.
- Recursively check if remaining string follows sum pattern
- Return true if any valid sequence is found, otherwise false
#include <bits/stdc++.h>
using namespace std;
// Checks whether num is valid or not, by
// checking first character and size
bool isValid(string num)
{
// the length of the string cannot be less than 1.
// If length > 1 and starts with 0, then invalid
if (num.size() > 1 && num[0] == '0')
return false;
return true;
}
// returns int value at pos string, if pos is
// out of bound then returns 0
int val(string a, int pos)
{
// since we are decrementing the pos,
// we must check if it is less than 0
if (pos < 0)
return 0;
// converting character to integer
return (a[pos] - '0');
}
// add two number in string form and return
// result as a string
string addString(string a, string b)
{
string sum = "";
int i = a.length() - 1;
int j = b.length() - 1;
int carry = 0;
// loop until both string get processed
while (i >= 0 || j >= 0) {
int t = val(a, i) + val(b, j) + carry;
sum += (t % 10 + '0');
carry = t / 10;
i--;
j--;
}
if (carry)
sum += (carry + '0');
reverse(sum.begin(), sum.end());
return sum;
}
// Recursive method to check c = a + b
bool checkAddition(string a, string b, string c)
{
// both first and second number should be valid
if (!isValid(a) || !isValid(b))
return false;
string sum = addString(a, b);
// if sum is same as c then direct return
if (sum == c)
return true;
/* if sum size is greater than c, then no
possible sequence further OR if c is not
prefix of sum string, then no possible
sequence further */
if (c.size() <= sum.size()
|| sum != c.substr(0, sum.size()))
return false;
else {
// next recursive call will have b as first
// number, sum as second number and string
// c as third number after removing prefix
// sum string from c
return checkAddition(b, sum,
c.substr(sum.size()));
}
}
// Method returns true if string is additive
bool isSumString(string &s)
{
int n = s.length();
// loop until l/2 only, because if first
// number is larger, then no possible sequence later
for (int i = 1; i <= n / 2; i++) {
for (int j = 1; j <= (n - i) / 2; j++) {
if (checkAddition(s.substr(0, i),
s.substr(i, j),
s.substr(i + j))) {
return true;
}
}
}
// If code execution reaches here, then string
// doesn't have any additive sequence
return false;
}
// Driver code
int main()
{
string s = "235813";
if (isSumString(s))
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}
import java.util.*;
class GFG {
// Checks whether num is valid or not, by
// checking first character and size
static boolean isValid(String num)
{
// the length of the string cannot be less than 1.
// If length > 1 and starts with 0, then invalid
if (num.length() > 1 && num.charAt(0) == '0')
return false;
return true;
}
// returns int value at pos string, if pos is
// out of bound then returns 0
static int val(String a, int pos)
{
// since we are decrementing the pos, we must check if it is less than 0
if (pos < 0)
return 0;
// converting character to integer
return (a.charAt(pos) - '0');
}
// add two number in string form and return
// result as a string
static String addString(String a, String b)
{
StringBuilder sum = new StringBuilder();
int i = a.length() - 1;
int j = b.length() - 1;
int carry = 0;
// loop until both string get processed
while (i >= 0 || j >= 0) {
int t = val(a, i) + val(b, j) + carry;
sum.append((char)((t % 10) + '0'));
carry = t / 10;
i--;
j--;
}
if (carry != 0)
sum.append((char)(carry + '0'));
return sum.reverse().toString();
}
// Recursive method to check c = a + b
static boolean checkAddition(String a, String b, String c)
{
// both first and second number should be valid
if (!isValid(a) || !isValid(b))
return false;
String sum = addString(a, b);
// if sum is same as c then direct return
if (sum.equals(c))
return true;
/* if sum size is greater than c, then no
possible sequence further OR if c is not
prefix of sum string, then no possible
sequence further */
if (c.length() <= sum.length()
|| !sum.equals(c.substring(0, sum.length())))
return false;
else {
// next recursive call will have b as first
// number, sum as second number and string
// c as third number after removing prefix
// sum string from c
return checkAddition(b, sum,
c.substring(sum.length()));
}
}
// Method returns true if string is additive
static boolean isSumString(String s)
{
int l = s.length();
// loop until l/2 only, because if first
// number is larger, then no possible sequence later
for (int i = 1; i <= l / 2; i++) {
for (int j = 1; j <= (l - i) / 2; j++) {
if (checkAddition(s.substring(0, i),
s.substring(i, i + j),
s.substring(i + j))) {
return true;
}
}
}
// If code execution reaches here, then string
// doesn't have any additive sequence
return false;
}
// Driver code
public static void main(String[] args)
{
String s = "235813";
if (isSumString(s))
System.out.println("true");
else
System.out.println("false");
}
}
# Checks whether num is valid or not, by
# checking first character and size
def isValid(num):
# the length of the string cannot be less than 1.
# If length > 1 and starts with 0, then invalid
if len(num) > 1 and num[0] == '0':
return False
return True
# returns int value at pos string, if pos is
# out of bound then returns 0
def val(a, pos):
# since we are decrementing the pos, we must check if it is less than 0
if pos < 0:
return 0
# converting character to integer
return int(a[pos])
# add two number in string form and return
# result as a string
def addString(a, b):
sum_str = ""
i = len(a) - 1
j = len(b) - 1
carry = 0
# loop until both string get processed
while i >= 0 or j >= 0:
t = val(a, i) + val(b, j) + carry
sum_str += str(t % 10)
carry = t // 10
i -= 1
j -= 1
if carry:
sum_str += str(carry)
return sum_str[::-1]
# Recursive method to check c = a + b
def checkAddition(a, b, c):
# both first and second number should be valid
if not isValid(a) or not isValid(b):
return False
sum_str = addString(a, b)
# if sum is same as c then direct return
if sum_str == c:
return True
if len(c) <= len(sum_str) or sum_str != c[:len(sum_str)]:
return False
else:
return checkAddition(b, sum_str, c[len(sum_str):])
# Method returns true if string is additive
def isSumString(s):
l = len(s)
for i in range(1, l // 2 + 1):
for j in range(1, (l - i) // 2 + 1):
if checkAddition(s[:i],
s[i:i + j],
s[i + j:]):
return True
return False
# Driver code
s = "235813"
if isSumString(s):
print("true")
else:
print("false")
using System;
class GFG {
// Checks whether num is valid or not, by
// checking first character and size
static bool isValid(string num)
{
if (num.Length > 1 && num[0] == '0')
return false;
return true;
}
// returns int value at pos string, if pos is
// out of bound then returns 0
static int val(string a, int pos)
{
if (pos < 0)
return 0;
return (a[pos] - '0');
}
// add two number in string form and return
// result as a string
static string addString(string a, string b)
{
string sum = "";
int i = a.Length - 1;
int j = b.Length - 1;
int carry = 0;
while (i >= 0 || j >= 0) {
int t = val(a, i) + val(b, j) + carry;
sum += (char)((t % 10) + '0');
carry = t / 10;
i--;
j--;
}
if (carry != 0)
sum += (char)(carry + '0');
char[] arr = sum.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
// Recursive method to check c = a + b
static bool checkAddition(string a, string b, string c)
{
if (!isValid(a) || !isValid(b))
return false;
string sum = addString(a, b);
if (sum == c)
return true;
if (c.Length <= sum.Length ||
sum != c.Substring(0, sum.Length))
return false;
else {
return checkAddition(b, sum,
c.Substring(sum.Length));
}
}
// Method returns true if string is additive
static bool isSumString(string s)
{
int l = s.Length;
for (int i = 1; i <= l / 2; i++) {
for (int j = 1; j <= (l - i) / 2; j++) {
if (checkAddition(s.Substring(0, i),
s.Substring(i, j),
s.Substring(i + j))) {
return true;
}
}
}
return false;
}
// Driver code
public static void Main()
{
string s = "235813";
if (isSumString(s))
Console.WriteLine("true");
else
Console.WriteLine("false");
}
}
// Checks whether num is valid or not, by
// checking first character and size
function isValid(num)
{
if (num.length > 1 && num[0] === '0')
return false;
return true;
}
// returns int value at pos string, if pos is
// out of bound then returns 0
function val(a, pos)
{
if (pos < 0)
return 0;
return parseInt(a[pos]);
}
// add two number in string form and return
// result as a string
function addString(a, b)
{
let sum = "";
let i = a.length - 1;
let j = b.length - 1;
let carry = 0;
while (i >= 0 || j >= 0) {
let t = val(a, i) + val(b, j) + carry;
sum += (t % 10).toString();
carry = Math.floor(t / 10);
i--;
j--;
}
if (carry)
sum += carry.toString();
return sum.split("").reverse().join("");
}
// Recursive method to check c = a + b
function checkAddition(a, b, c)
{
if (!isValid(a) || !isValid(b))
return false;
let sum = addString(a, b);
if (sum === c)
return true;
if (c.length <= sum.length ||
sum !== c.substring(0, sum.length))
return false;
else {
return checkAddition(b, sum,
c.substring(sum.length));
}
}
// Method returns true if string is additive
function isSumString(s)
{
let l = s.length;
for (let i = 1; i <= Math.floor(l / 2); i++) {
for (let j = 1; j <= Math.floor((l - i) / 2); j++) {
if (checkAddition(s.substring(0, i),
s.substring(i, i + j),
s.substring(i + j))) {
return true;
}
}
}
return false;
}
// Driver code
let s = "235813";
if (isSumString(s))
console.log("true");
else
console.log("false");
Output
true
[Better Approach] Iteration + String Simulation ā O(n³) Time and O(n) Space
The idea is to simulate the additive sequence iteratively. We try all possible splits for the first two numbers and then keep generating the next number using string addition.
At each step, we check whether the generated sum matches the corresponding substring in the original string. If the sequence continues till the end, it is valid.
- Try all possible splits for first and second numbers
- Iteratively generate next numbers using string addition
- Check if generated sum matches the next part of the string
- Continue until string ends or mismatch occurs and return result
#include <bits/stdc++.h>
using namespace std;
// Standard function to add two numbers given as strings (O(length))
string strAdd(const string &s1, const string &s2) {
string sum;
sum.reserve(max(s1.size(), s2.size()) + 1);
int c = 0; // carry digit
// Traverse both strings from right to left
for (int i = (int)s1.size() - 1, j = (int)s2.size() - 1; i >= 0 || j >= 0; i--, j--) {
int a = (i >= 0) ? (s1[i] - '0') : 0;
int b = (j >= 0) ? (s2[j] - '0') : 0;
int t = a + b + c;
sum.push_back(t % 10 + '0'); // append at the back (O(1))
c = t / 10;
}
if (c) sum.push_back(c + '0');
reverse(sum.begin(), sum.end()); // reverse once at the end
return sum;
}
// Checks whether the first two numbers f and s generate the rest of num
bool isAdditiveNumberUtil(const string &num, string f, string s) {
int n = num.size();
int i = f.size() + s.size(); // start index of the next number
// At least one more number (the third) must exist
if (i >= n) return false;
while (i < n) {
// Generate the next number
string sum = strAdd(f, s);
// The sum must match the string exactly at position i (no substr copy)
if (num.compare(i, sum.size(), sum) != 0)
return false;
// Move forward in the sequence
f = s;
s = sum;
i += sum.size();
}
// Valid only if the string was consumed exactly
return i == n;
}
// Returns true if the string is an additive sequence
bool isSumString(string &s) {
int len = s.size();
if (len < 3) return false;
// Try all possible splits for the first and second numbers
for (int i = 0; i < len; i++) {
// First number has a leading zero -> all longer first numbers are invalid too
if (i > 0 && s[0] == '0') break;
for (int j = i + 1; j < len; j++) {
// Second number has a leading zero -> longer ones are invalid too
if (j > i + 1 && s[i + 1] == '0') break;
int len1 = i + 1;
int len2 = j - i;
// Third number is at least max(len1, len2) long; if not enough
// characters remain, longer second numbers will not work either
if (len - (j + 1) < max(len1, len2)) break;
if (isAdditiveNumberUtil(s, s.substr(0, len1), s.substr(i + 1, len2)))
return true;
}
}
return false;
}
// Driver code
int main() {
string s = "235813";
if (isSumString(s))
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}
import java.util.*;
class GFG {
// Standard function to add two numbers given as strings (O(length))
static String strAdd(String s1, String s2) {
StringBuilder sum = new StringBuilder();
int c = 0; // carry digit
// Traverse both strings from right to left
for (int i = s1.length() - 1, j = s2.length() - 1; i >= 0 || j >= 0; i--, j--) {
int a = i >= 0 ? (s1.charAt(i) - '0') : 0;
int b = j >= 0 ? (s2.charAt(j) - '0') : 0;
int t = a + b + c;
sum.append((char) (t % 10 + '0')); // append at the back (O(1))
c = t / 10;
}
if (c != 0) sum.append((char) (c + '0'));
return sum.reverse().toString(); // reverse once at the end
}
// Checks whether the first two numbers f and s generate the rest of num
static boolean isAdditiveNumberUtil(String num, String f, String s) {
int n = num.length();
int i = f.length() + s.length(); // start index of the next number
// At least one more number (the third) must exist
if (i >= n) return false;
while (i < n) {
// Generate the next number
String sum = strAdd(f, s);
// The sum must match the string exactly at position i (no substring copy)
if (!num.startsWith(sum, i))
return false;
// Move forward in the sequence
f = s;
s = sum;
i += sum.length();
}
// Valid only if the string was consumed exactly
return i == n;
}
// Returns true if the string is an additive sequence
static boolean isSumString(String s) {
int len = s.length();
if (len < 3) return false;
// Try all possible splits for the first and second numbers
for (int i = 0; i < len; i++) {
// First number has a leading zero -> longer first numbers are invalid too
if (i > 0 && s.charAt(0) == '0') break;
for (int j = i + 1; j < len; j++) {
// Second number has a leading zero -> longer ones are invalid too
if (j > i + 1 && s.charAt(i + 1) == '0') break;
int len1 = i + 1;
int len2 = j - i;
// Third number is at least max(len1, len2) long; if not enough
// characters remain, longer second numbers will not work either
if (len - (j + 1) < Math.max(len1, len2)) break;
if (isAdditiveNumberUtil(s, s.substring(0, len1), s.substring(i + 1, j + 1)))
return true;
}
}
return false;
}
// Driver code
public static void main(String[] args) {
String s = "235813";
if (isSumString(s))
System.out.println("true");
else
System.out.println("false");
}
}
# Standard function to add two numbers given as strings
def strAdd(s1, s2):
res = []
c = 0 # carry digit
i = len(s1) - 1
j = len(s2) - 1
# Traverse both strings from right to left
while i >= 0 or j >= 0:
a = ord(s1[i]) - 48 if i >= 0 else 0
b = ord(s2[j]) - 48 if j >= 0 else 0
t = a + b + c
res.append(chr(t % 10 + 48)) # append at the back (O(1))
c = t // 10
i -= 1
j -= 1
if c:
res.append(str(c))
return "".join(reversed(res)) # reverse once at the end
# Checks whether the first two numbers f and s generate the rest of num
def isAdditiveNumberUtil(num, f, s):
n = len(num)
i = len(f) + len(s) # start index of the next number
# At least one more number (the third) must exist
if i >= n:
return False
while i < n:
# Generate the next number
sum_str = strAdd(f, s)
# The sum must match the string exactly at position i (no slicing copy)
if not num.startswith(sum_str, i):
return False
# Move forward in the sequence
f = s
s = sum_str
i += len(sum_str)
# Valid only if the string was consumed exactly
return i == n
# Returns True if the string is an additive sequence
def isSumString(s):
length = len(s)
if length < 3:
return False
# Try all possible splits for the first and second numbers
for i in range(length):
# First number has a leading zero -> longer first numbers are invalid too
if i > 0 and s[0] == '0':
break
for j in range(i + 1, length):
# Second number has a leading zero -> longer ones are invalid too
if j > i + 1 and s[i + 1] == '0':
break
len1 = i + 1
len2 = j - i
# Third number is at least max(len1, len2) long; if not enough
# characters remain, longer second numbers will not work either
if length - (j + 1) < max(len1, len2):
break
if isAdditiveNumberUtil(s, s[:len1], s[i + 1:j + 1]):
return True
return False
# Driver code
s = "235813"
if isSumString(s):
print("true")
else:
print("false")
using System;
using System.Text;
class GFG {
// Standard function to add two numbers given as strings (O(length))
static string strAdd(string s1, string s2) {
StringBuilder sum = new StringBuilder();
int c = 0; // carry digit
// Traverse both strings from right to left
for (int i = s1.Length - 1, j = s2.Length - 1; i >= 0 || j >= 0; i--, j--) {
int a = i >= 0 ? (s1[i] - '0') : 0;
int b = j >= 0 ? (s2[j] - '0') : 0;
int t = a + b + c;
sum.Append((char)(t % 10 + '0')); // append at the back (O(1))
c = t / 10;
}
if (c != 0) sum.Append((char)(c + '0'));
// Reverse once at the end
char[] arr = sum.ToString().ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
// Checks whether num has the substring 'sum' exactly at position pos (no copy)
static bool matchAt(string num, int pos, string sum) {
if (pos + sum.Length > num.Length) return false;
return string.CompareOrdinal(num, pos, sum, 0, sum.Length) == 0;
}
// Checks whether the first two numbers f and s generate the rest of num
static bool isAdditiveNumberUtil(string num, string f, string s) {
int n = num.Length;
int i = f.Length + s.Length; // start index of the next number
// At least one more number (the third) must exist
if (i >= n) return false;
while (i < n) {
// Generate the next number
string sum = strAdd(f, s);
// The sum must match the string exactly at position i
if (!matchAt(num, i, sum))
return false;
// Move forward in the sequence
f = s;
s = sum;
i += sum.Length;
}
// Valid only if the string was consumed exactly
return i == n;
}
// Returns true if the string is an additive sequence
static bool isSumString(string s) {
int len = s.Length;
if (len < 3) return false;
// Try all possible splits for the first and second numbers
for (int i = 0; i < len; i++) {
// First number has a leading zero -> longer first numbers are invalid too
if (i > 0 && s[0] == '0') break;
for (int j = i + 1; j < len; j++) {
// Second number has a leading zero -> longer ones are invalid too
if (j > i + 1 && s[i + 1] == '0') break;
int len1 = i + 1;
int len2 = j - i;
// Third number is at least max(len1, len2) long; if not enough
// characters remain, longer second numbers will not work either
if (len - (j + 1) < Math.Max(len1, len2)) break;
if (isAdditiveNumberUtil(s, s.Substring(0, len1), s.Substring(i + 1, len2)))
return true;
}
}
return false;
}
// Driver code
public static void Main() {
string s = "235813";
if (isSumString(s))
Console.WriteLine("true");
else
Console.WriteLine("false");
}
}
// Standard function to add two numbers given as strings (O(length))
function strAdd(s1, s2) {
let res = [];
let c = 0; // carry digit
// Traverse both strings from right to left
for (let i = s1.length - 1, j = s2.length - 1; i >= 0 || j >= 0; i--, j--) {
let a = i >= 0 ? (s1.charCodeAt(i) - 48) : 0;
let b = j >= 0 ? (s2.charCodeAt(j) - 48) : 0;
let t = a + b + c;
res.push(t % 10); // append at the back (O(1))
c = t >= 10 ? 1 : 0;
}
if (c) res.push(c);
return res.reverse().join(""); // reverse once at the end
}
// Checks whether num has the string 'sum' exactly at position pos (no substring copy)
function matchAt(num, pos, sum) {
if (pos + sum.length > num.length) return false;
for (let k = 0; k < sum.length; k++) {
if (num.charCodeAt(pos + k) !== sum.charCodeAt(k)) return false;
}
return true;
}
// Checks whether the first two numbers f and s generate the rest of num
function isAdditiveNumberUtil(num, f, s) {
let n = num.length;
let i = f.length + s.length; // start index of the next number
// At least one more number (the third) must exist
if (i >= n) return false;
while (i < n) {
// Generate the next number
let sum = strAdd(f, s);
// The sum must match the string exactly at position i
if (!matchAt(num, i, sum))
return false;
// Move forward in the sequence
f = s;
s = sum;
i += sum.length;
}
// Valid only if the string was consumed exactly
return i === n;
}
// Returns true if the string is an additive sequence
function isSumString(s) {
let len = s.length;
if (len < 3) return false;
// Try all possible splits for the first and second numbers
for (let i = 0; i < len; i++) {
// First number has a leading zero -> longer first numbers are invalid too
if (i > 0 && s[0] === '0') break;
for (let j = i + 1; j < len; j++) {
// Second number has a leading zero -> longer ones are invalid too
if (j > i + 1 && s[i + 1] === '0') break;
let len1 = i + 1;
let len2 = j - i;
// Third number is at least max(len1, len2) long; if not enough
// characters remain, longer second numbers will not work either
if (len - (j + 1) < Math.max(len1, len2)) break;
if (isAdditiveNumberUtil(s, s.substring(0, len1), s.substring(i + 1, j + 1)))
return true;
}
}
return false;
}
// Driver code
let s = "235813";
if (isSumString(s))
console.log("true");
else
console.log("false");
Output
true