zoukankan      html  css  js  c++  java
  • leetcode常规算法题复盘(第十期)——将数组拆分成斐波那契序列

    题目原文

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

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

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

    • 0 <= F[i] <= 2^31 - 1,(也就是说,每个整数都符合 32 位有符号整数类型);
    • F.length >= 3
    • 对于所有的0 <= i < F.length - 2,都有 F[i] + F[i+1] = F[i+2] 成立。

    另外,请注意,将字符串拆分成小块时,每个块的数字一定不要以零开头,除非这个块是数字 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. 1 <= S.length <= 200
    2. 字符串 S 中只含有数字。

    尝试解答

    python在int转换大于2^31-1的数值的时候竟然不会报错!python天下第一!

     1 class Solution:
     2     def splitIntoFibonacci(self, S):
     3         ans = list()
     4         def backTrack(index):
     5             if index==len(S):
     6                 return len(ans)>=3
     7             cur = 0
     8             for i in range(index,len(S)):
     9                 if i>index and S[index]=="0":
    10                     break
    11                 cur = cur*10+int(S[i])
    12                 if cur>(2**31)-1:
    13                     break
    14                 if len(ans)<2 or ans[-2]+ans[-1]==cur:
    15                     ans.append(cur)
    16                     if backTrack(i+1):
    17                         return True
    18                     ans.pop(-1)
    19                 elif len(ans)>=2 and ans[-2]+ans[-1]==cur:
    20                     break
    21             return False
    22         if backTrack(0):
    23             return ans
    24         else:
    25             return list()

     

    标准题解

    这道题漂亮的解法是点到为止的传统功夫——递归回溯下的DFS。

    回溯 + 剪枝

    将给定的字符串拆分成斐波那契式序列,可以通过回溯的方法实现。

    使用列表存储拆分出的数,回溯过程中维护该列表的元素,列表初始为空。遍历字符串的所有可能的前缀,作为当前被拆分出的数,然后对剩余部分继续拆分,直到整个字符串拆分完毕。

    根据斐波那契式序列的要求,从第 333 个数开始,每个数都等于前 222 个数的和,因此从第 333 个数开始,需要判断拆分出的数是否等于前 222 个数的和,只有满足要求时才进行拆分,否则不进行拆分。

    回溯过程中,还有三处可以进行剪枝操作。

        拆分出的数如果不是 000,则不能以 000 开头,因此如果字符串剩下的部分以 000 开头,就不需要考虑拆分出长度大于 111 的数,因为长度大于 111 的数以 000 开头是不符合要求的,不可能继续拆分得到斐波那契式序列;

        拆分出的数必须符合 323232 位有符号整数类型,即每个数必须在 [0,231−1][0,2^{31}-1][0,231−1] 的范围内,如果拆分出的数大于 231−12^{31}-1231−1,则不符合要求,长度更大的数的数值也一定更大,一定也大于 231−12^{31}-1231−1,因此不可能继续拆分得到斐波那契式序列;

        如果列表中至少有 222 个数,并且拆分出的数已经大于最后 222 个数的和,就不需要继续尝试拆分了。

    当整个字符串拆分完毕时,如果列表中至少有 333 个数,则得到一个符合要求的斐波那契式序列,返回列表。如果没有找到符合要求的斐波那契式序列,则返回空列表。

    实现方面,回溯需要带返回值,表示是否存在符合要求的斐波那契式序列。

    作者:LeetCode-Solution
    链接:https://leetcode-cn.com/problems/split-array-into-fibonacci-sequence/solution/jiang-shu-zu-chai-fen-cheng-fei-bo-na-qi-ts6c/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

     1 class Solution:
     2     def splitIntoFibonacci(self, S: str) -> List[int]:
     3         ans = list()
     4 
     5         def backtrack(index: int):
     6             if index == len(S):
     7                 return len(ans) >= 3
     8             
     9             curr = 0
    10             for i in range(index, len(S)):
    11                 if i > index and S[index] == "0":
    12                     break
    13                 curr = curr * 10 + ord(S[i]) - ord("0")
    14                 if curr > 2**31 - 1:
    15                     break
    16                 
    17                 if len(ans) < 2 or curr == ans[-2] + ans[-1]:
    18                     ans.append(curr)
    19                     if backtrack(i + 1):
    20                         return True
    21                     ans.pop()
    22                 elif len(ans) > 2 and curr > ans[-2] + ans[-1]:
    23                     break
    24         
    25             return False
    26         
    27         backtrack(0)
    28         return ans
    29 
    30 
    31 #作者:LeetCode-Solution
    32 #链接:https://leetcode-cn.com/problems/split-array-into-fibonacci-sequence/solution/jiang-shu-zu-chai-fen-cheng-fei-bo-na-qi-ts6c/
    33 #来源:力扣(LeetCode)
    34 #著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
     1 class Solution {
     2 public:
     3     vector<int> ans;
     4     bool check(){
     5         if(ans.size() < 3) return true;
     6         return (long long)ans.back() == (long long)ans[ans.size() - 2] + (long long)ans[ans.size() - 3]; 
     7     }
     8     bool dfs(string& s, int ind){
     9         if(ind >= s.size()) return ans.size() > 2; // 出口,ans.size()大于2表示找到一个合法的答案了
    10         if(s[ind] == '0'){
    11             ans.push_back(0);
    12             if(check() && dfs(s, ind + 1)) return true; // 本次选择合法并且后续搜索也找到答案
    13             ans.pop_back();
    14             return false; // 回溯
    15         }
    16         long long cur = 0; // 枚举所有不超过INT_MAX的数作为本层选择
    17         while(ind < s.size()){
    18             cur = cur * 10 + s[ind++] - '0';
    19             if(cur > INT_MAX) return false; // 枚举已经超过INT_MAX却还没找打答案,搜索失败
    20             ans.push_back(cur);
    21             if(check() && dfs(s, ind)) return true; // 本次选择合法并且后续搜索也找到答案
    22             ans.pop_back();
    23         }
    24         return false; // 回溯
    25     }
    26     vector<int> splitIntoFibonacci(string s) {
    27         if(dfs(s, 0)) return ans;
    28         return {};
    29     }
    30 };
    31 
    32 
    33 //作者:Monologue-S
    34 //链接:https://leetcode-cn.com/problems/split-array-into-fibonacci-sequence/solution/cshen-sou-jian-dan-30xing-4ms-by-monolog-y0bz/
    35 //来源:力扣(LeetCode)
    36 //著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    复杂度分析

        时间复杂度:O(nlog⁡2C)O(n log^2 C)O(nlog2C),其中 nnn 是字符串的长度,CCC 是题目规定的整数范围 231−12^{31}-1231−1。在回溯的过程中,实际上真正进行「回溯」的只有前 222 个数,而从第 333 个数开始,整个斐波那契数列是可以被唯一确定的,整个回溯过程只起到验证(而不是枚举)的作用。对于前 222 个数,它们的位数不能超过 ⌊log⁡10C⌋lfloor log_{10} C floor⌊log10​C⌋,那么枚举的空间为 O(log⁡2C)O(log^2 C)O(log2C);对于后面的所有数,回溯的过程是没有「分支」的,因此时间复杂度为 O(n)O(n)O(n),相乘即可得到总时间复杂度 O(nlog⁡2C)O(n log^2 C)O(nlog2C)。

        空间复杂度:O(n)O(n)O(n),其中 nnn 是字符串的长度。除了返回值以外,空间复杂度主要取决于回溯过程中的递归调用层数,最大为 nnn。

    作者:LeetCode-Solution
    链接:https://leetcode-cn.com/problems/split-array-into-fibonacci-sequence/solution/jiang-shu-zu-chai-fen-cheng-fei-bo-na-qi-ts6c/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    react 脚手架cra的注意事项,以及脚手架生成目录的分析,以及四个脚本命令
    react组件传值的方式大全
    leetcode——367.有效的完全平方数
    leetcode——69.x的平方根
    leetcode——169.求众数
    leetcode——100.相同的树
    leetcode——172.阶乘后的零
    leetcode——35.搜索插入位置
    leetcode——26.删除排序数组中的重复项
    leetcode——5.最长回文子串
  • 原文地址:https://www.cnblogs.com/monkiki/p/14111112.html
Copyright © 2011-2022 走看看