[バックトラック] [リートコード]グレイコード

トピック:

グレイコードは、2つの連続する値が1桁だけ異なる2進数システムです。

コードの合計桁数を表す負でない整数nが与えられた場合、そのグレイコードシーケンスを出力します。複数の異なる回答がある場合でも、そのうちの1つを返すだけで済みます。

グレイコードシーケンスは0で始まる必要があります。

例1:

入力:2
出力:[0,1,3,2]
説明:
00から0
。01から1
。11から3
10から2

与えられたnに対して、そのグレイコードシーケンスは一意ではありません。
たとえば、[0,2,3,1]も有効なグレイコードシーケンスです。

00から0
10から2
11 - 3
01から1

ソース:

89.グレイコーディング

問題解決のアイデア1:バックトラック

中間結果を保存するパスを定義し、条件が満たされるとすぐに出力します。

  • 結果は条件を満たしています:パス内の数に達しました
  • 再帰呼び出し条件:前の番号のグレイコードがパスにない場合、それらは再帰的です。

現在の番号が000の場合、次のグレイコードは001,010,100になります。コード内の灰色の関数に注目し、p番目の桁を変更して戻ります。最初にp番目の桁が0か1かを判別します。0の場合、OR演算を1に変更できます。1の場合。 AND演算は0に変更できます。

class Solution {
public:
    vector<int> result;
    vector<int> path;
    bool ok;
    vector<int> grayCode(int n) {
        vector<bool> flag(1<<n, false); // 记录数字是否已在结果列表中
        ok = false;
        path.push_back(0);
        flag[0] = true;
        back(n, flag);
        return result;
    }
    void back(int n, vector<bool>& flag) {
        if (path.size() == flag.size()) {
            result = path;
            ok = true;
            return;
        }
        int pre = path[path.size() - 1]; // 结果列表中最后一个数字
        for (int i = 0; i < n; i++) {
            if (ok) break;
            int k = gray(pre, i); // 最后一个数字的改变第i位后的数字
            if (!flag[k]) {
                flag[k] = true;
                path.push_back(k);
                back(n, flag);
                path.pop_back();
                flag[k] = false;
            }
        }
    }
    int gray(int v, int p) {
        int a = (0x1 << p);
        if ((a & v) == 0) {
            return v | a;
        } else {
            return v & (~a);
        }
    }
};

問題解決のアイデア2:法を見つける

遡及的なコード提出により、運用効率が非常に低いことがわかりました。実行時間:20ミリ秒で、すべてのC ++提出でユーザーの12.37%を打ち負かしました。

不思議なことに、私は解決策を読みに行きましたが、この質問にはまだ従うべきパターンがあることがわかりました。コードを書きませんでした。以下に見つけたパターンをリストしました。

n = 1の場合、結果は[0,1]、

n = 2の場合、次の3つのステップに分けられます。

  1. n = 1の結果を取得し、[0,1]を取得します。
  2. [0,1]を取り、それをミラーにコピーして[1,0]を取得します。2つは[0,1 | 1、0]にマージされ、中央に記号|が付いて、それをaと呼びます。今のところミラー。
  3. ミラーの左側の各番号の先頭に0を追加し、右側に1を追加して、[00、01 | 11、10]を取得します。これが結果です。

n = 3,4,5 ...の場合、上記の3つの手順を順番に繰り返します。

n = 3の場合、

  1. n = 2の結果を取得し、[00、01、11、10]を取得します。
  2. [00、01、11、10]を見て、コピーを作成して[10、11、01、00]を取得します。2つを組み合わせて[00、01、11、10 | 10、11、01、 00]。
  3. ミラーの左側の各数値の先頭に0を追加し、右側に1を追加して、[000、001、011、010 | 110、111、101、100]を取得します。これが結果です。

おすすめ

転載: blog.csdn.net/hbuxiaoshe/article/details/115123734