1. 题目:https://leetcode-cn.com/problems/additive-number
2. 思路:
假如我有一个函数,dfs(int pos, long long pre1, long long pre2),它能够告诉我,已经前两个数字分别是pre1, pre2,从给定字符串的pos位开始,是否存在一个序列满足
题目要求,如果满足,返回true给我,否则返回false给我。
于是,我可以在主函数中从字符串的前i位中取出第一个数字pre1,从i~j位取出第二个数字pre2,然后调用dfs(j+1, pre1, pre2),一旦有一次dfs返回true, 说明该
取法满足题意,即得到最后答案=true。如果i遍历完了所有的位置,还没有找到一种满足的方案,则返回最后结果false.
3. 需要注意的地方:
3.1 字符串长度 [1, 35],所以存放数字需要用long long八字节类型整数,不能用int。
3.2 每个数字都不能有前缀0
4. 代码:
typedef long long ll;
int len;
char* num;
// bool dfs(int pos, ll pre1, ll pre2)
// 此递归函数表示:已经前两个数字分别为pre1, pre2,从字符串的pos位开始,是否满足题目要求的。
// 满足则返回true, 否则返回false。
bool dfs(int pos, ll pre1, ll pre2) {
// 1. cur表示当前我们寻找的"第三个数"
ll cur = 0;
// 2. 确定cur的最大下标范围
int index1 = len;
if (num[pos] == '0') { //如果首位是0,那么cur只能是0,因为题目要求任何数字都不能有前缀0
index1 = pos+1;
}
for(int i=pos; i<index1; i++) {
cur = cur*10+num[i]-'0';
if (pre1 + pre2 == cur) {
// 如果正好读完了整个字符串,或者 从字符串的i+1位开始是否能找到可以满足题意的情况
if (i+1 == len || dfs(i+1, pre2, cur)) {
return true;
}
} else if (pre1 + pre2 < cur) { //如果前两个数字的和 已经小于当前的数字,则无需继续循环,因为cur只会越来越大。
return false;
}
}
// 如果前两个数字的和 始终大于cur,说明无法找到下一个数字 = pre1+pre2
return false;
}
bool isAdditiveNumber(char * num2){
ll max(ll a, ll b);
// 1. 设置全局变量,给递归函数用,set global variables for recursive method.
len = strlen(num2);
num = num2;
// 2. 手工先取出 前两个数字
ll pre1=0, pre2=0;
// index1表示第一个数字的最后一位下标,index2表示第二个数字最后一位的下标。
int index1 = 0, index2 = 0;
// 2.1 第一个数字的下标范围
if (num[0] == '0') {
index1 = 1; //
} else {
index1 = len/2; // 第一个数字的长度必然<len/2
}
// 2.2 设置第一个数字
for (int i=0; i<index1; i++) {
pre1 = pre1*10+num[i]-'0';
pre2 = 0;
// 2.3 第二个数字的下标范围
int j = i+1;
if (num[j] == '0') {
index2 = i+1;
} else {
index2 = len-2; // 至少留一个位给下一个数
}
// 2.4 设置第二个数字
for (; j<=index2; j++) {
pre2 = pre2*10+num[j]-'0';
// 判断从j+1位开始,是否能够找到后序的满足题意的情况。
if (dfs(j+1, pre1, pre2)) {
return true;
}
}
}
return false;
}
ll max(ll a, ll b) {
return a>b?a:b;
}