数组拆分成斐波那契序列-算法题

题意:给定一个字符串,判断能否将其拆分成斐波那契序列,如果可以则输出任意一个。
其中斐波那契序列的num[i]均满足 0 <= num[i] < 2^31
传送门

输入:num = “1101111”
输出:[11,0,11,11]
解释:输出[110,1,111]也可以。

题解一:其实直接暴力就行,枚举序列的前2个数,判断后面的序列是否满足即可,就是写得有点丑。

vector<int> splitIntoFibonacci(string num) {
    auto add = [](string a, string b) {
        string ret;
        if (a.length() < b.length()) swap(a, b);
        int flag = 0;
        for (int i = 0; i < b.length(); ++i) {
            int num = a[a.length()-1-i]-'0'+b[b.length()-1-i]-'0'+flag;
            flag = num/10;
            num %= 10;
            ret = char(num+'0') + ret;
        }
        for (int i = b.length(); i < a.length(); ++i) {
            int num = a[a.length()-1-i]-'0'+flag;
            flag = num/10;
            num %= 10;
            ret = char(num+'0') + ret;
        }
        if (flag) ret = char(flag+'0') + ret;
        return ret;
    };

    int len = num.length();
    vector<int> ret;

    function<bool(string,string,int)> is_f = [&](string a, string b, int id){
        if (id == len) return true;
        if (ret.empty()) {
            ret.push_back(stoi(a));
            ret.push_back(stoi(b));
        }
        string sum = add(a, b);
        long isum = stol(sum), ia = stol(a), ib = stol(b);
        if (isum > INT_MAX || ia > INT_MAX || ib > INT_MAX) return false;
        ret.push_back(isum);
        int i = id, j = 0;
        for (; i < len && j < sum.length(); ++i, ++j) {
            if (sum[j] != num[i]) break;
        }
        if (j < sum.length()) return false;
        return is_f(b, sum, i);
    };

    for (int i = 1; i < len-2; ++i) {
        string a = num.substr(0, i);
        if (stol(a) > INT_MAX) break;
        if (num[i] == '0') {
            if (is_f(a, "0", i+1))
                return ret;
            ret.clear();
            continue;
        }
        for (int j = i; j < len-1; ++j) {
            string b = num.substr(i, j-i+1);
            if (stol(b) > INT_MAX) break;
            if (is_f(a, b, j+1))
                return ret;
            ret.clear();
        }
        if (num[0] == '0') break;
    }
    return ret;
}

题解二:回溯,直接递归,代码短好多,也好看一点
backtrack(id, sum, prev)表示当前从下标id开始,找到和为sum的数,且上一个数为prev;

  • 如果存在和为sum的数,则push_back这个sum,然后从sum的下一个下标开始,下一步找sum+prev的数;
  • 如果不存在,直接退出,返回false并且回溯(pop_back);
vector<int> splitIntoFibonacci(string num) {
    int len = num.length();
    vector<int> ret;
    function<bool(int,long,int)> backtrack = [&](int id, long sum, int prev){
        if (id == len) return ret.size() >= 3;
        long cur = 0;
        for (int i = id; i < len; ++i) {
            cur = cur * 10 + num[i] - '0';
            if (cur > INT_MAX) 
                break;
            if (ret.size() >= 2) {
                if (cur < sum) continue;
                if (cur > sum) break;
            }
            ret.push_back(cur);
            if (backtrack(i+1, prev+cur, cur))
                return true;
            ret.pop_back();
            if (num[id] == '0') break;
        }
        return false;
    };
    backtrack(0, 0, 0);
    return ret;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值