【LeetCode】842. 将数组拆分成斐波那契序列

172 篇文章 4 订阅
148 篇文章 3 订阅

一、题目描述

给定一个数字字符串 S,比如 S = “123456579”,我们可以将它分成斐波那契式的序列 [123, 456, 579]。

形式上,斐波那契式序列是一个非负整数列表 F,且满足:

  1. 0 <= F[i] <= 2^31 - 1,(也就是说,每个整数都符合 32 位有符号整数类型);
    F.length >= 3;
  2. 对于所有的0 <= i < F.length - 2,都有 F[i] + F[i+1] = F[i+2] 成立。
  3. 另外,请注意,将字符串拆分成小块时,每个块的数字一定不要以零开头,除非这个块是数字 0 本身。

返回从 S 拆分出来的任意一组斐波那契式的序列块,如果不能拆分则返回 []。

示例 1:

输入:"123456579"
输出:[123,456,579]

示例 2:

输入: "11235813"
输出: [1,1,2,3,5,8,13]

示例 3:

输入: "112358130"
输出: []
解释: 这项任务无法完成。

示例 4:

输入:"0123"
输出:[]
解释:每个块的数字不能以零开头,因此 "01","2","3" 不是有效答案。

示例 5:

输入: "1101111"
输出: [110, 1, 111]
解释: 输出 [11,0,11,11] 也同样被接受。

提示:

1 <= S.length <= 200
字符串 S 中只含有数字。

二、解题思路 & 代码

2.1 暴力法

想法

数组的前两个元素唯一决定了后面的数组元素。

算法

对于每种可能的前两个元素,假设没有前导零,遍历剩余的字符串。对于每个情况,我们希望得到小于等于 2^31 - 1 的数,且是前两个数字之和。

class Solution(object):
    def splitIntoFibonacci(self, S):
        for i in xrange(min(10, len(S))):
            x = S[:i+1]
            if x != '0' and x.startswith('0'): break
            a = int(x)
            for j in xrange(i+1, min(i+10, len(S))):
                y = S[i+1: j+1]
                if y != '0' and y.startswith('0'): break
                b = int(y)
                fib = [a, b]
                k = j + 1
                while k < len(S):
                    nxt = fib[-1] + fib[-2]
                    nxtS = str(nxt)
                    if nxt <= 2**31 - 1 and S[k:].startswith(nxtS):
                        k += len(nxtS)
                        fib.append(nxt)
                    else:
                        break
                else:
                    if len(fib) >= 3:
                        return fib
        return []


复杂度分析

  1. 时间复杂度: O ( N 2 ) O(N^2) O(N2),其中 N 是 S 的长度,按照要求结果的长度都是 O(1) 的。
  2. 空间复杂度:O(N)。
2.2 回溯 + 剪枝

主要是回溯过程中的剪枝优化,减去了值大于2 ** 31 - 1和不符合F[i] + F[i + 1] = F[i + 2]的部分。还有就是new_value以’0’开头并且长度大于1的部分,需要注意’0’是符合条件的数字。

class Solution:
    def splitIntoFibonacci(self, S: str) -> List[int]:
        n = len(S)

        res = []

        def backtrack(index, temp):
            if index == n:
                if self._is_fibonacci(temp):
                    res.append(temp)
                return

            for i in range(index, n):
                new_value = S[index:i + 1]
                if int(new_value) > 2 ** 31 - 1:
                    break
                if not (new_value.startswith('0') and len(new_value) > 1):
                    if len(temp) >= 2 and int(new_value) == (temp[-1] + temp[-2]):
                        backtrack(i + 1, temp + [int(new_value)])
                    elif len(temp) < 2:
                        backtrack(i + 1, temp + [int(new_value)])

        backtrack(0, [])

        return res[0] if res else []

    def _is_fibonacci(self, temp):
        if len(temp) < 3:
            return False
        for i in range(2, len(temp)):
            if temp[i] != (temp[i - 1] + temp[i - 2]):
                return False

        return True


参考:

  1. LeetCode 官方题解
  2. LeetCode题解
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值