image-20220110131554278

读题

原题链接:LeetCode 306. 累加数

题目要求我们在找到一个长串的数的分割方案使得这个数满足分割得到的数组满足累加序列的性质,通过示例我们很容易理解其含义

需要注意两点:

  1. 数字不会以0开头(除数字0外)
  2. 数据可能会很大

解题思路

  1. 通过经验我们容易发现分割方案的题很容易与深度优先搜索(DFS | 回溯法)联系,但是这里的数据范围1 <= num.length <= 35着实让我捏了把汗,不考虑剪枝的复杂度为 2352^{35} 远远超过我们能承受的范围
  2. 然后我们可以考虑一下累加序列有没有特别的性质可作为突破口,这时我们可以发现:对于一个合理的累加序列如果前两个数字确定那么整个序列也就可以通过这两个数推出
  3. 所以我们就可以只枚举前两个数然后检查后续的数字是否可能分割成满足累加序列的数字来判断整体是否满足累加序列的性质了
  4. 我们考虑特殊情况:如果我们枚举到一个数以0开头那么它只能是0,即当测试过数不能是0后就表示这样的分割方案是不合理的
  5. 关于数据可能过大的问题: 对于一个待分割的累加数我们可以发现只有当把这个数分割为三个部分时才会得到单个数数最大的情况,而对于题中num.length <= 35的条件,使得单个数最大的分割情况就是将数划分为12位 11位 12位这样最大的数也就只有12位数,而long long最大能表示完17 位的数,所有用long long存储即可

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
bool isAdditiveNumber(string num) {
int len = num.length();
if(len < 3) return false;

for(long long i = 0, num1 = 0; i < len-2 && i < 12; i++){
num1 = num1*10+(num[i]-'0');

for(long long j = i+1, num2 = 0; j < len-1 && j < 24; j++){
num2 = num2*10+(num[j]-'0');

long long a = num1, b = num2, c = 0;
for(int k = j+1, start = j+1; k < len; k++){
c = c*10+(num[k]-'0');
if(c > a+b) break;
else if(c == a+b){
if(k == len-1) return true;
a = b, b = c, c = 0;
start = k+1;
}
else if(num[start] == '0') break;
}

if(num[i+1] == '0') break;
}
if(num[0] == '0') break;
}

return false;
}
};

带注释版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Solution {
public:
bool isAdditiveNumber(string num) {
int len = num.length();
if(len < 3) return false;

//枚举第一个数,这里设置上限12位
for(long long i = 0, num1 = 0; i < len-2 && i < 12; i++){
num1 = num1*10+(num[i]-'0');

//枚举第二个数,同样上限为12位
for(long long j = i+1, num2 = 0; j < len-1 && j-i < 12; j++){
num2 = num2*10+(num[j]-'0');

long long a = num1, b = num2, c = 0;

//start记录了c是以哪个数开头
for(int k = j+1, start = j+1; k < len; k++){
c = c*10+(num[k]-'0');

if(c > a+b) break;
else if(c == a+b){
//如果这时恰好为结尾就返回真
if(k == len-1) return true;

a = b, b = c, c = 0;
start = k+1;
}
//如果c时以0开头,那么经过一局测试后不满足则抛弃
else if(num[start] == '0') break;
}

//如果num2时以0开头,那么经过一局测试后不满足则抛弃
if(num[i+1] == '0') break;
}

//如果num1时以0开头,那么经过一局测试后不满足则抛弃
if(num[0] == '0') break;
}

return false;
}
};

润了, 润了,继续去水题了 ٩(๑òωó๑)۶ ♡♡♡

img