累加数 是一个字符串,组成它的数字可以形成累加序列。
一个有效的 累加序列 必须 至少 包含 3 个数。除了最开始的两个数以外,序列中的每个后续数字必须是它之前两个数字之和。
给你一个只包含数字 '0'-'9'
的字符串,编写一个算法来判断给定输入是否是 累加数 。如果是,返回 true
;否则,返回 false
。
说明:累加序列里的数,除数字 0 之外,不会 以 0 开头,所以不会出现 1, 2, 03
或者 1, 02, 3
的情况。
示例 1:
输入:"112358"
输出:true 解释:累加序列为:1, 1, 2, 3, 5, 8
。1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8
示例 2:
输入:
"199100199"
输出:true 解释:累加序列为:1, 99, 100, 199。
1 + 99 = 100, 99 + 100 = 199
提示:
1 <= num.length <= 35
num
仅由数字(0
-9
)组成
进阶:你计划如何处理由过大的整数输入导致的溢出?
官方题解:
class Solution:
def isAdditiveNumber(self, num: str) -> bool:
n = len(num)#字符串的长度
#一个有效的 累加序列 必须 至少 包含 3 个数,所以 0 和 n-1 是第二个数不能取到的,要留给前面和后面的数
#遍历第二个数的可能的开始和结尾的范围
for secondStart in range(1, n - 1):#第二个数的开始范围
if num[0] == '0' and secondStart != 1:#累加序列里的数,除数字 0 之外,不会 以 0 开头,num[0] == '0'则secondStart只能为1,其他情况就不用在进行判断
break
for secondEnd in range(secondStart, n - 1):#第二个数的结尾范围,从secondStart+1开始遍历
if num[secondStart] == '0' and secondStart != secondEnd:#如果num[secondStart] == '0',那么第二个数必须为0,第二个数的开始即结尾
break
if self.valid(secondStart, secondEnd, num):#一个累加序列,当它的第一个数字和第二个数字以及总长度确定后,这整个累加序列也就确定了。
return True
return False
#判断累加序列是否有效
def valid(self, secondStart: int, secondEnd: int, num: str) -> bool:
n = len(num)#字符串的长度
firstStart, firstEnd = 0, secondStart - 1#确定第一个数字,得到第二个数字的开始位置就可以求到第一个数字了
while secondEnd <= n - 1:#secondEnd在有效范围内时
third = self.stringAdd(num, firstStart, firstEnd, secondStart, secondEnd)#第一个数和第二个数相加得到第三个数
thirdStart = secondEnd + 1#第三个数的起始位置
thirdEnd = secondEnd + len(third)#第三个数的终止位置
if thirdEnd >= n or num[thirdStart : thirdEnd + 1] != third:#越界或不等
break
if thirdEnd == n - 1:#只有三个数
return True
#第二个数的第三个数变成新的第一、二个数
firstStart, firstEnd = secondStart, secondEnd
secondStart, secondEnd = thirdStart, thirdEnd
return False
#将传入的第一个数和第二个数相加
def stringAdd(self, s:str, firstStart: int, firstEnd: int, secondStart: int, secondEnd: int) -> str:
third = []#空列表
carry, cur = 0, 0#进位,当前值
while firstEnd >= firstStart or secondEnd >= secondStart or carry != 0:#加上第一个和第二个数
cur = carry#上一次的进位是当前值
#每次加上两个数的同一位
if firstEnd >= firstStart:#第一个数成立 123
cur += ord(s[firstEnd]) - ord('0')#ord将字符转换为整数
firstEnd -= 1
if secondEnd >= secondStart:#第二个数成立236
cur += ord(s[secondEnd]) - ord('0')
secondEnd -= 1
carry = cur // 10#进位
cur %= 10#当前位的值
third.append(chr(cur + ord('0')))
return ''.join(third[::-1])#将列表的元素反转并拼接