leetcode
leetcode 751 ~ 800
将数组拆分成斐波那契序列

将数组拆分成斐波那契序列

难度:

标签:

题目描述

代码结果

运行时间: 28 ms, 内存: 16.1 MB


/*
 * 思路:
 * 1. 使用递归和Java Stream API进行斐波那契数列的查找。
 * 2. 尝试从字符串的每个位置开始分割,使用Stream检查每个片段是否符合条件。
 */
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class SolutionStream {
    public List<Integer> splitIntoFibonacci(String num) {
        List<Integer> result = new ArrayList<>();
        backtrack(num, result, 0);
        return result;
    }

    private boolean backtrack(String num, List<Integer> result, int index) {
        if (index == num.length() && result.size() >= 3) {
            return true;
        }
        return IntStream.range(index, num.length())
            .filter(i -> !(num.charAt(index) == '0' && i > index))
            .mapToObj(i -> num.substring(index, i + 1))
            .map(Long::parseLong)
            .filter(numL -> numL <= Integer.MAX_VALUE)
            .filter(numL -> {
                int size = result.size();
                return size <= 1 || numL == result.get(size - 1) + result.get(size - 2);
            })
            .anyMatch(numL -> {
                result.add(numL.intValue());
                boolean found = backtrack(num, result, index + String.valueOf(numL).length());
                if (!found) {
                    result.remove(result.size() - 1);
                }
                return found;
            });
    }
}

解释

方法:

题解通过使用回溯法来尝试构建斐波那契序列。首先定义一个辅助函数 dfs(i),其中 i 表示当前正在处理的数字的起始位置。如果 i 等于字符串的长度且答案列表中至少有三个数,说明已经成功构建了一个序列,函数返回 True。然后逐个检查可能的数字,如果遇到以 '0' 开头的数字(并且长度超过1),则跳出循环。对每一个可能的数字,检查是否符合斐波那契序列的要求:1) 数字不能超过 2^31 - 1;2) 如果列表中已有至少两个数,该数必须等于最后两个数的和。如果当前数字满足要求,将其加入到序列中并递归调用 dfs(j+1)。如果递归调用返回 True,表示找到了合法的序列,当前函数也返回 True。如果当前路径不行,则将最后一个数字从序列中移除(回溯),尝试下一个可能的数字。如果所有可能都尝试完毕,返回 False。

时间复杂度:

O(2^n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在解决这个问题时选择使用回溯法而不是其他算法如动态规划?
回溯法适用于解决决策树的问题,尤其是在不确定符合条件的斐波那契数列数目和组合情况时。这个问题的解空间不固定且需要尝试多种组合来构建合法的斐波那契序列。动态规划更适合在有明确子问题重叠和最优子结构的问题上使用,而在斐波那契序列的构建中,每个决策点的选择直接影响后续路径,且没有重叠子问题,因此使用回溯法更为合适。
🦆
在处理以 '0' 开头的数字时,为什么只有当数字长度超过1时才跳过,而单个'0'是被接受的?
在许多数值系统中,前导零是无意义的,并且可能导致解析错误或不一致。然而,数字'0'本身是有效的并且是斐波那契序列的一个合法数字。因此,在算法中允许单独的'0'作为序列中的一个元素,但如果一个数字以'0'开头且长度超过1,如'01'或'001',则这种表示不被接受,因为它不符合数字的标准表示方式。
🦆
函数中检查`x > 2**31 - 1`的原因是什么,考虑到Python的int类型是动态大小的,这一检查的目的是什么?
虽然Python的整数类型是动态的,可以处理非常大的数,但在实际问题中常常需要考虑实际应用的环境。例如,在LeetCode中,通常假设整数范围是有限的,符合常见的32位整数范围。检查`x > 2**31 - 1`是为了确保解决方案在所有编程环境中都是有效的,特别是在那些整数大小有固定上限的编程语言中,这可以防止整数溢出错误。此外,这也符合斐波那契序列在实际应用中的一些限制,避免生成过大的数字。
🦆
在`ans`列表中需要至少两个数时,使用`ans[-2] + ans[-1] == x`来检查当前数字x是否可以添加到列表中。这种方法是否可能因为整数溢出而导致问题?
在Python中,由于整数类型是动态的,理论上加法操作不会导致传统意义上的整数溢出。Python会自动处理大于32位的整数,因此不会出现溢出错误。但是,在其他一些静态类型语言中,如C++或Java,这种操作确实可能导致溢出。因此,这种情况下在Python中使用是安全的,但如果在其他语言实现相同逻辑时,需要额外的检查来确保不会溢出。

相关问题

累加数

累加数 是一个字符串,组成它的数字可以形成累加序列。

一个有效的 累加序列 必须 至少 包含 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)组成

 

进阶:你计划如何处理由过大的整数输入导致的溢出?

斐波那契数

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 01 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1

给定 n ,请计算 F(n)

 

示例 1:

输入:n = 2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1

示例 2:

输入:n = 3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2

示例 3:

输入:n = 4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3

 

提示:

  • 0 <= n <= 30