491、バックトラッキングアルゴリズムソリューションは配列をフィボナッチ数列に分割します

ここに画像の説明を挿入します

あなたがより多くのアルゴリズムの質問を見たい場合は、上記のQRコードをスキャンし、私の微信公式アカウント「に従うことができるデータ構造とアルゴリズム」。現在までに、私がしている500の以上のアルゴリズムの質問更新公式アカウントで持っているそのうちのいくつかを、 pdfドキュメントに分類されています。、現在、合計800ページ以上あります(そして今後も増え続けます)。公式アカウントのキーワード「pdf」に返信してダウンロードできます。


問題の説明

S = "123456579"などの数値文字列Sが与えられると、フィボナッチのようなシーケンスに分割できます[ 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:

入力:「112​​35813」

出力:[1,1,2,3,5,8,13]

例3:

入力:「112​​358130」

出力:[]

説明:このタスクは完了できません。

例4:

入力:「0123」

出力:[]

説明:各ブロックの番号をゼロから始めることはできないため、「01」、「2」、および「3」は有効な回答ではありません。

例5:

入力:「1101111」

出力:[110、1、111]

説明:出力[11,0,11,11]も受け入れられます。


促す:

  • 1 <= S。長さ<= 200
  • 文字列Sには数字のみが含まれます。

バックトラッキングアルゴリズムソリューション

この質問は、文字列Sをいくつかの部分文字列に分割することであり、これらの部分文字列はフィボナッチ数列の関係を満たします。この問題については、バックトラッキングアルゴリズムを使用して解決できます。バックトラッキングアルゴリズムは、実際には継続的な試行のプロセスです。試行が成功すると成功します。試行が失敗すると、前の手順に戻ります。注前のステップに戻ると、状態を前のステップの状態に復元します。ここでは、バックトラッキングアルゴリズムについてはあまり紹介していません。バックトラッキングアルゴリズムの問​​題解決のアイデアについては、450を参照してください。バックトラッキングアルゴリズムとは何ですか?一見するわかりますが、書くと役に立たなくなります。


バックトラッキングアルゴリズムには、実際には古典的なテンプレートがあります

private void backtrack("原始参数") {
    
    
    //终止条件(递归必须要有终止条件)
    if ("终止条件") {
    
    
        //一些逻辑操作(可有可无,视情况而定)
        return;
    }

    for (int i = "for循环开始的参数"; i < "for循环结束的参数"; i++) {
    
    
        //一些逻辑操作(可有可无,视情况而定)

        //做出选择

        //递归
        backtrack("新的参数");
        //一些逻辑操作(可有可无,视情况而定)

        //撤销选择
    }
}

この質問についても同じことが言えます。まず、文字列を継続的にインターセプトして、フィボナッチ数列を形成できるかどうかを確認します。できない場合は、前の手順に戻ります。可能な場合は、下に進みます。詳細については、下の図を見てください。これは例1を参照して描かれた絵ですが、数字が多いと絵が大きすぎて描くことができないため、数字は短くなり、124557になります。

ここに画像の説明を挿入します

上記の原則を理解してください。コードははるかに単純です。コードを見てみましょう。

public List<Integer> splitIntoFibonacci(String S) {
    
    
    List<Integer> res = new ArrayList<>();
    backtrack(S.toCharArray(), res, 0);
    return res;
}

public boolean backtrack(char[] digit, List<Integer> res, int index) {
    
    
    //边界条件判断,如果截取完了,并且res长度大于等于3,表示找到了一个组合。
    if (index == digit.length && res.size() >= 3) {
    
    
        return true;
    }
    for (int i = index; i < digit.length; i++) {
    
    
        //两位以上的数字不能以0开头
        if (digit[index] == '0' && i > index) {
    
    
            break;
        }
        //截取字符串转化为数字
        long num = subDigit(digit, index, i + 1);
        //如果截取的数字大于int的最大值,则终止截取
        if (num > Integer.MAX_VALUE) {
    
    
            break;
        }
        int size = res.size();
        //如果截取的数字大于res中前两个数字的和,说明这次截取的太大,直接终止,因为后面越截取越大
        if (size >= 2 && num > res.get(size - 1) + res.get(size - 2)) {
    
    
            break;
        }
        if (size <= 1 || num == res.get(size - 1) + res.get(size - 2)) {
    
    
            //把数字num添加到集合res中
            res.add((int) num);
            //如果找到了就直接返回
            if (backtrack(digit, res, i + 1))
                return true;
            //如果没找到,就会走回溯这一步,然后把上一步添加到集合res中的数字给移除掉
            res.remove(res.size() - 1);
        }
    }
    return false;
}

//相当于截取字符串S中的子串然后转换为十进制数字
private long subDigit(char[] digit, int start, int end) {
    
    
    long res = 0;
    for (int i = start; i < end; i++) {
    
    
        res = res * 10 + digit[i] - '0';
    }
    return res;
}

総括する

実際にテンプレートを持っているアルゴリズムの質問タイプは多くありませんが、バックトラッキングアルゴリズムはその1つです。異なるタイプの質問を異なる方法で変更する必要があるだけです。このテンプレートをマスターしている限り、多くのバックトラッキングアルゴリズムをわずかに変更できます。質問の種類。簡単に作成できます。

おすすめ

転載: blog.csdn.net/abcdef314159/article/details/112498301