Additive number is a string whose digits can form 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.
For example:
"112358"
is an additive number because 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
"199100199"
is also an additive number, the additive sequence is:
1, 99, 100, 199
.
1 + 99 = 100, 99 + 100 = 199
Note: Numbers in the additive sequence cannot have leading zeros, so sequence 1, 2, 03
or 1, 02, 3
is invalid.
Given a string containing only digits '0'-'9'
, write a function to determine if it's an additive number.
Follow up:
How would you handle overflow for very large input integers?
一眼看上去应该用dfs,但是和一般的不太一样,这里要首先选两个数出来,第三个数及以后才满足加和关系,所以分开来处理。
取数的位数本身就是剪枝条件,例如第一个数取了三位数,第二个数随意取(假设取了一位),加和的数位数肯定是大于等于前两个数中位数较大的,如果剩下的都不够三位数,肯定是不满足关系的。还有第一个数选好了,第二个数的位数最多大到与和数一样,否则是不可能成立的。由于选取前两个数是一个过程,后面迭代选取尝试构成加和序列又是另外的过程,后面的迭代搜索每次搜索两个数,那么例如“123”这样只能选出一个数就构成加和序列的情况单独处理一下。另外截取串的时候如果有前导的0,直接忽略掉,如果只是一个0,是要考虑的。
public class Solution {
int len;
public boolean isAdditiveNumber(String num)
{
len=num.length();
if(len<3)
return false;
return dfs(num, 0, 0, 0);
}
private boolean dfs(String num,long prenum,long preprenum,int curpos)
{
if(curpos==len)
return true;
for(int i=1;i<=(len-curpos)/3;i++)
for(int j=1;j<=(len-i)/2;j++)
{
String num1=num.substring(curpos,curpos+i);
if(num1.length()>1&&num1.charAt(0)=='0')
continue;
String num2=num.substring(curpos+i,curpos+i+j);
if(num2.length()>1&&num2.charAt(0)=='0')
continue;
if(dfsaux(num, Long.parseLong(num2), Long.parseLong(num1), curpos+i+j, Math.max(num1.length(), num2.length())+1))
return true;
}
return false;
}
private boolean dfsaux(String num,long prenum,long preprenum,int curpos,int searchmaxlen)
{
if(curpos==len)
return true;
for(int i=1;i+curpos<=len&&i<=searchmaxlen;i++)
for(int j=i;j<=searchmaxlen;j++)
{
String num1=num.substring(curpos,curpos+i);
if(num1.length()>1&&num1.charAt(0)=='0')
continue;
long n1=Long.parseLong(num1);
if(i+j+curpos>len)
{
String sn1=String.valueOf(n1);
if(n1==(prenum+preprenum))
return true;
continue;
}
String num2=num.substring(curpos+i,curpos+i+j);
if(num2.length()>1&&num2.charAt(0)=='0')
continue;
long n2=Long.parseLong(num2);
if(n1==(prenum+preprenum)&&n2==n1+prenum)
if(dfsaux(num, n2, n1, curpos+i+j,Math.max(num1.length(), num2.length())+1))
return true;
}
return false;
}
}
-----------------------------------------------------------------------------------
简洁一点的版本
https://discuss.leetcode.com/topic/30453/java-very-straightforward-solution-with-detailed-explanation
The idea is quite straightforward:
-
Choose the first number
A
, it can be the leftmost1
up toi
digits.i<=(L-1)/2
because the third number should be at least as long as the first number -
Choose the second number
B
, it can be the leftmost1
up toj
digits excluding the first number. the limit forj
is a little bit tricky, because we don't know whetherA
orB
is longer. The remaining string (with lengthL-j
) after excludingA
andB
should have a length of at least max(lengthA
, lengthB
), where lengthA
=i
and lengthB
=j-i
, thusL-j >= max(j-i, i)
-
Calls the recursive checker function and returns true if passes the checker function, or continue to the next choice of
B
(A
) until there is no more choice forB
orA
, in which case returns a false.
public boolean isAdditiveNumber(String num) {
int L = num.length();
// choose the first number A
for(int i=1; i<=(L-1)/2; i++) {
// A cannot start with a 0 if its length is more than 1
if(num.charAt(0) == '0' && i>=2) break; //previous code: continue;
// choose the second number B
for(int j=i+1; L-j>=j-i && L-j>=i; j++) {
// B cannot start with a 0 if its length is more than 1
if(num.charAt(i) == '0' && j-i>=2) break; // previous: continue;
long num1 = Long.parseLong(num.substring(0, i)); // A
long num2 = Long.parseLong(num.substring(i, j)); // B
String substr = num.substring(j); // remaining string
if(isAdditive(substr, num1, num2)) return true; // return true if passes isAdditive test
// else continue; // continue for loop if does not pass isAdditive test
}
}
return false; // does not pass isAdditive test, thus is not additive
}
// Recursively checks if a string is additive
public boolean isAdditive(String str, long num1, long num2) {
if(str.equals("")) return true; // reaches the end of string means a yes
long sum = num1+num2;
String s = ((Long)sum).toString();
if(!str.startsWith(s)) return false; // if string does not start with sum of num1 and num2, returns false
return isAdditive(str.substring(s.length()), num2, sum); // recursively checks the remaining string
}