インタビューでよくある質問: バックトラッキング アルゴリズム インクリメンタル サブシーケンスとフル パーミュテーション II

前書き:
バックトラッキング アルゴリズムが何なのかわからない場合は、バックトラッキング アルゴリズムの基本原理とフレームワークをすぐに理解できるように、このバックトラッキングの概要を読むことをお勧めします。

増加するサブシーケンス

整数 num の配列を指定すると、その配列内で少なくとも 2 つの要素を持つ個別の増加するサブシーケンスをすべて検索して返します。回答は任意の順序で返すことができます。
配列には、2 つの整数が等しいなど、繰り返しの要素が含まれる場合もあり、増加シーケンスの特殊なケースと見なすこともできます。

出典: LeetCode Incremental Subsequence
ここに画像の説明を挿入
質問の意味から、次の 2 つの要件が得られます。

  • 3 つ以上の要素を含むインクリメントサブシーケンス
  • サブシーケンスはサブシーケンスと同じであってはなりません
  • 繰り返しの数字も使用可能

この種のトピックのように、要素を順番に取得し、要素を保存して合計セットを形成する必要がある場合、問題中に別のセットを取得するためにロールバックする必要がある場合があります。バックトラック方式を使用します。では、どのようにバックトラックするのでしょうか? 以下の図の分析を見てみましょう。例として[ 4,7,6,7 ] を使用します。
ここに画像の説明を挿入
ここに画像の説明を挿入

  1. コレクションのサブセット条件をバックトラッキングする質問の意味によると、サブシーケンスの数が 2 以上である
    限り、次のことがわかります。
  2. バックトラッキング終了条件
    終了条件はnums.size()に達することです
  3. 単一層の検索ロジック
    図からわかるように、シーケンス内に繰り返しの数値がある可能性がありますが、単一の層で同じ数値を取得することはできません。同じ数値を取得する場合は、同じサブセットが存在するはずです。単層レイヤーは重複排除する必要がある

単一レイヤーの重複排除 ここでは、マークされたコンテナunowned_set<int> を使用して、すでに出現した数値を格納します。


コードは以下のように表示されます。

class Solution {
    
    
public:
    vector<vector<int>> arr;
    vector<int> _arr;

    void BackTracking(vector<int>& nums,int begin)
    {
    
    
        if(_arr.size()>=2)//只要数据>=2就存储,我们这里不需要return
        {
    
    
            arr.push_back(_arr);
        }
        unordered_set<int> use;//标记容器
        for(int i=begin;i<nums.size();i++)
        {
    
    
        //如果是空直接存放,然后判断别的关系
            if((!_arr.empty() && _arr.back()>nums[i]) || use.find(nums[i])!=use.end())
            {
    
    
                continue;
            }
            _arr.push_back(nums[i]);
            use.insert(nums[i]);
            BackTracking(nums,i+1);//不能重复使用单个数据,所以我们需要i+1
            _arr.pop_back();
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
    
    
        BackTracking(nums,0);
        return arr;
    }
};

フルアレンジⅡ

反復する数値を含む可能性のあるシーケンス nums を指定すると、反復しないすべての完全な順列を任意の順序で返します。

出典: LeetCodeフルアレンジメント II

この問題はフルアレンジの発展版で、以前は繰り返し要素がなかったのに、今は繰り返し要素があるのですが、どう解けばいいでしょうか?

ここに画像の説明を挿入
この質問は、サブシーケンスを増やすという前の質問に似ていますが、単一レイヤーの重複排除も必要です。以下の図を見てください。 前の要素のコレクションと比較して、配置
ここに画像の説明を挿入
内のすべての要素を使用する必要があるため、ループするたびに条件が両方とも 0 ですが、使用済みの要素を使用しないようにするには、使用済みの要素ごとに 1 つのマーカー、単一レイヤーの重複排除の配列を設定する必要があります。同じレイヤーで同じ要素を使用することは、同じデータを 2 回再帰し、同じサブセットを生成することと同等です。

  • 最初にすべての要素を並べ替えます
  • タグ配列
  • 単一レイヤーの重複排除

コードは以下のように表示されます。

class Solution {
    
    
public:
    vector<vector<int>> arr;
    vector<int> _arr;
    void BackTracking(vector<int>& nums,vector<bool>& use)
    {
    
    
        if(_arr.size()==nums.size())
        {
    
    
            arr.push_back(_arr);
            return;
        }
        for(int i=0;i<nums.size();i++)
        {
    
    
        	//单层去重,及判断元素是否使用过
            if(i>0 && nums[i]==nums[i-1] && use[i-1]==false)
            {
    
    
                continue;
            }
            if(use[i]==false)
            {
    
    
                use[i]=true;
                _arr.push_back(nums[i]);
                BackTracking(nums,use);
                _arr.pop_back();
                use[i]=false;
            }
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
    
    
        sort(nums.begin(),nums.end());//需要排序,为去重做准备
        vector<bool> use(nums.size(),false);
        BackTracking(nums,use);
        return arr;
    }
};

おすすめ

転載: blog.csdn.net/DEXTERFUTIAN/article/details/129799563