[LeetCode] Additive Number 加法数
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.
Given a string containing only digits '0'-'9'
, write a function to determine if it's an additive number.
Note: Numbers in the additive sequence cannot have leading zeros, so sequence 1, 2, 03
or 1, 02, 3
is invalid.
Example 1:
Input:"112358"
Output: true
Explanation: 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
Example 2:
Input:"199100199"
Output: true
Explanation: The additive sequence is:1, 99, 100, 199
.
1 + 99 = 100, 99 + 100 = 199
Follow up:
How would you handle overflow for very large input integers?
Credits:
Special thanks to @jeantimex for adding this problem and creating all test cases.
这道题定义了一种加法数,就是至少含有三个数字,除去前两个数外,每个数字都是前面两个数字的和,题目中给了许多例子,也限定了一些不合法的情况,比如两位数以上不能以0开头等等,让我们来判断一个数是否是加法数。目光犀利的童鞋应该一眼就能看出来,这尼玛不就是斐波那契数组么,跟另一道 Split Array into Fibonacci Sequence 简直不要太像啊。只不过那道题要返回一种组合方式,而这道题只是问能否拆成斐波那契数列。
开始我还想是否能用动态规划来解,可是发现不会写状态转移方程,只得作罢。其实这题可用Brute Force的思想来解,我们让第一个数字先从一位开始,第二个数字从一位,两位,往高位开始搜索,前两个数字确定了,相加得到第三位数字,三个数组排列起来形成一个字符串,和原字符串长度相比,如果小于原长度,那么取出上一次计算的第二个和第三个数,当做新一次计算的前两个数,用相同的方法得到第三个数,再加入当前字符串,再和原字符串长度相比,以此类推,直到当前字符串长度不小于原字符串长度,比较两者是否相同,相同返回true,不相同则继续循环。如果所有情况都遍历完了还是没有返回true,则说明不是Additive Number,返回false,参见代码如下:
解法一:
class Solution {
public:
bool isAdditiveNumber(string num) {
for (int i = ; i < num.size(); ++i) {
string s1 = num.substr(, i);
if (s1.size() > && s1[] == '') break;
for (int j = i + ; j < num.size(); ++j) {
string s2 = num.substr(i, j - i);
long d1 = stol(s1), d2 = stol(s2);
if ((s2.size() > && s2[] == '')) break;
long next = d1 + d2;
string nextStr = to_string(next);
if (nextStr != num.substr(j, nextStr.length())) continue; // optimization here
string allStr = s1 + s2 + nextStr;
while (allStr.size() < num.size()) {
d1 = d2;
d2 = next;
next = d1 + d2;
nextStr = to_string(next);
allStr += nextStr;
}
if (allStr == num) return true;
}
}
return false;
}
};
此题还有递归解法,博主最先尝试的是跟那道 Split Array into Fibonacci Sequence 一样的递归方法,虽然这道题不用返回组合方式,但是我们仍可以使用一样的递归来做,只不过这里的结果res是一个布尔型的全局变量,当我们找到一组符合题意的组合了之后,就将结果res设置为true,这样一旦再进入递归函数时,只要res为true了,就直接返回即可。之后的部分就基本相同了,可以参见 Split Array into Fibonacci Sequence 中的讲解,注意稍有不同的地方是,这里拆分出来的数字是可以超过整型int范围的,但是貌似不会超过长整型long的范围,所以我们可以加一个检测str的长度大于19就break,因为long的十进制数长度是19位,参见代码如下:
解法二:
class Solution {
public:
bool isAdditiveNumber(string num) {
bool res = false;
vector<long> out;
helper(num, , out, res);
return res;
}
void helper(string& num, int start, vector<long>& out, bool& res) {
if (res) return;
if (start >= num.size()) {
if (out.size() >= ) res = true;
return;
}
for (int i = start; i < num.size(); ++i) {
string str = num.substr(start, i - start + );
if ((str.size() > && str[] == '') || str.size() > ) break;
long curNum = stol(str), n = out.size();
if (out.size() >= && curNum != out[n - ] + out[n - ]) continue;
out.push_back(curNum);
helper(num, i + , out, res);
out.pop_back();
}
}
};
由于这道题并不需要我们返回具体的组合方式,所以也可以不使用上面的写法,而是不停的用当前的两个数,去拼后面的数字,一旦拼不出来了,直接返回false。跟解法一类似,首先用两个for循环来确定前两个数字,然后将后面的整体提取出来,和当前的两个数字一起调用递归,若递归返回true了,则直接返回true,否则继续遍历。
在递归函数中,还是首先检验是否存在leading zeros,然后将 num1 和 num2 分别转为长整型long,相加后再转回字符串,存入sumStr,这时候看sumStr是否和num相等,是的话直接返回true。否则再来检验,若sumStr的长度大于等于num了,返回false,或者在num中取跟sumStr长度相等的子串,若不等于sumStr,说明无法拼出来,也返回false。若都没返回的话,就再次调用递归,不过这次num要去掉和sumStr长度相等的子串,留下后面的部分,此时带入递归的两个数字要变成 num2 和 sumStr,继续跟后面的比较,参见代码如下:
解法三:
class Solution {
public:
bool isAdditiveNumber(string num) {
for (int i = ; i < num.size(); ++i) {
string s1 = num.substr(, i);
if (s1.size() > && s1[] == ) break;
for (int j = i + ; j < num.size(); ++j){
string s2 = num.substr(i, j - i);
if (s2.size() > && s2[] == ) break;
if(helper(num.substr(j), s1, s2)) return true;
}
}
return false;
}
bool helper(string num, string num1, string num2){
if ((num1.size() > && num1[] == '') || (num2.size() > && num2[] == '')) return false;
string sumStr = to_string(stol(num1) + stol(num2));
if (sumStr == num) return true;
if (sumStr.size() >= num.size() || num.substr(, sumStr.size()) != sumStr) return false;
return helper(num.substr(sumStr.size()), num2, sumStr);
}
};
题目中有个 follow up 说是让我们handle超大整数的溢出情况,那么我们想,上面的解法中哪块可能溢出啊,当然只有将子串转为长整型long的时候,假如此时字符串特别长,甚至超出了长整型的范围,那么我们就不能用stol了,此时就不能转换了,那么我们只能强行将两个字符串相加了,这里用的又是另外一道题目 Add Strings 的知识点了,这样我们就完美的避开了可能溢出的情况了,参见代码如下:
解法四:
// Follow up, handle overflow for very large input integers.
class Solution {
public:
bool isAdditiveNumber(string num) {
for (int i = ; i < num.size(); ++i) {
string s1 = num.substr(, i);
if (s1.size() > && s1[] == ) break;
for (int j = i + ; j < num.size(); ++j){
string s2 = num.substr(i, j - i);
if (s2.size() > && s2[] == ) break;
if(helper(num.substr(j), s1, s2)) return true;
}
}
return false;
}
bool helper(string num, string num1, string num2){
if ((num1.size() > && num1[] == '') || (num2.size() > && num2[] == '')) return false;
string sumStr = add(num1, num2);
if (sumStr == num) return true;
if (sumStr.size() >= num.size() || num.substr(, sumStr.size()) != sumStr) return false;
return helper(num.substr(sumStr.size()), num2, sumStr);
}
string add(string num1, string num2) {
string res;
int i = (int)num1.size() - , j = (int)num2.size() - , carry = ;
while (i >= || j >= ) {
int val1 = (i >= ) ? (num1[i--] - '') : ;
int val2 = (j >= ) ? (num2[j--] - '') : ;
int sum = val1 + val2 + carry;
res.push_back(sum % + '');
carry = sum / ;
}
if (carry) res.push_back(carry + '');
reverse(res.begin(), res.end());
return res;
}
};
类似题目:
Split Array into Fibonacci Sequence
参考资料:
https://leetcode.com/problems/additive-number/
https://leetcode.com/problems/additive-number/discuss/75567/Java-Recursive-and-Iterative-Solutions
https://leetcode.com/problems/additive-number/discuss/75704/My-Simple-C%2B%2B-Non-recursion-Solution
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Additive Number 加法数的更多相关文章
- 306 Additive Number 加法数
Additive number is a string whose digits can form additive sequence.A valid additive sequence should ...
- [LeetCode] Additive Number
Af first I read the title as "Addictive Number". Anyway, this problem can be solved elegan ...
- LeetCode(306) Additive Number
题目 Additive number is a string whose digits can form additive sequence. A valid additive sequence sh ...
- 【LeetCode】306. Additive Number 解题报告(Python)
[LeetCode]306. Additive Number 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http: ...
- 【刷题-LeetCode】306. Additive Number
Additive Number Additive number is a string whose digits can form additive sequence. A valid additiv ...
- Leetcode 306. Additive Number
Additive number is a string whose digits can form additive sequence. A valid additive sequence shoul ...
- [LeetCode] 306. Additive Number [Medium]
306. Additive Number class Solution { private: string stringAddition(string &a, string &b) { ...
- 【LeetCode】306. Additive Number
题目: Additive number is a string whose digits can form additive sequence. A valid additive sequence s ...
- 306. Additive Number
题目: Additive number is a string whose digits can form additive sequence. A valid additive sequence s ...
随机推荐
- java笔记--理解java类加载器以及ClassLoader类
类加载器概述: java类的加载是由虚拟机来完成的,虚拟机把描述类的Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成能被java虚拟机直接使用的java类型,这就是虚拟机的类加载机制 ...
- IE6+未知尺寸元素水平垂直居中
首先讨论在IE8以上(也就是支持伪元素after的基础上)的2种情况 当有一段不知道长度大小的文字在你面前,你需要使它垂直居中的时候,你肯定会想到:1.text-align:center;水平居中没错 ...
- [php]laravel框架容器管理的一些要点
本文面向php语言的laravel框架的用户,介绍一些laravel框架里面容器管理方面的使用要点.文章很长,但是内容应该很有用,希望有需要的朋友能看到.php经验有限,不到位的地方,欢迎帮忙指正. ...
- Nancy之实现API的功能
0x01.前言 现阶段,用来实现API的可能大部分用的是ASP.NET Web API或者是ASP.NET MVC,毕竟是微软官方出产的,用的人也多. 但是呢,NancyFx也是一个很不错的选择.毕竟 ...
- 如何在一个页面添加多个不同的kindeditor编辑器
kindeditor官方下载地址:http://kindeditor.net/down.php (入门必看)kindeditor官方文档:http://kindeditor.net/doc.ph ...
- C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试
在上篇<C#开发微信门户及应用(22)-微信小店的开发和使用>里面介绍了一些微信小店的基础知识,以及对应的对象模型,本篇继续微信小店的主题,介绍其中API接口的封装和测试使用.微信小店的相 ...
- C#开发微信门户及应用(1)--开始使用微信接口
微信应用如火如荼,很多公司都希望搭上信息快车,这个是一个商机,也是一个技术的方向,因此,有空研究下.学习下微信的相关开发,也就成为日常计划的重要事情之一了.本系列文章希望从一个循序渐进的角度上,全面介 ...
- Spring+ibatis动态管理数据源
Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性.而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时 ...
- 高性能 TCP & UDP 通信框架 HP-Socket v3.4.1
HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Del ...
- JAVA的序列化和持久化的区别与联系
持久化(Persistence) 即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘).持久化的主要应用是将内存中的对象存储在关系型的数据库中,当然也可以存储在磁盘文件中.XML数据文 ...