サブシーケンスの増加 (バックトラッキング)

質問の説明

整数配列を指定します nums 。配列内のさまざまな増加サブシーケンスをすべて検索して返します。増加サブシーケンスには少なくとも 2 つあります。 要素 。回答は 任意の順序 で返すことができます。

配列には繰り返し要素が含まれる場合があります。2 つの整数が等しい場合、それは増加シーケンスの特殊なケースと見なすこともできます。

サンプル入力

例 1:

输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]

例 2:

输入:nums = [4,4,3,2,1]
输出:[[4,4]]

ヒント:

  • 1 <= nums.length <= 15
  • -100 <= nums[i] <= 100

答え

図に示すように、この問題でバックトラッキング手法を使用する場合、次の 2 つの問題を解決する必要があります。

(バックトラッキング方法の使用の詳細については、 組み合わせ (バックトラッキング + プルーニング、図) - CSDN ブログ を参照してください)あ>

  • シーケンスの増分を決定する方法
  • バックトラバーサルを実行する方法重複を削除する

バックトラッキング手法を使用する場合、次のように、パス配列を使用してトラバーサル中にパス上の各ノードを保存し、 res を使用して最終結果を保存します。

    vector<int> path;//保存当前结果
    vector<vector<int>> res;//保存最终结果

増加しないシーケンスを削除する

バックトラッキング メソッドを使用して nums を走査する場合、パス配列を使用して現在の走査結果を保存するため、 については、パス配列の最後の要素と比較してそのサイズを決定するだけで済みます。つまり次に通過する要素 num[i]

If nums[i]>=path.back() は、 現在の要素 nums[i] を次のパスに追加することを意味します。 path 配列内でシーケンスは増加し続けることができます。その後、パスに nums[i] を追加できます。配列 ;

そうでない場合は、現在の要素 nums[i] をパス配列に追加した後、シーケンスが増加し続けることができないことを意味します。 、ただ nums[i] をパス 配列に追加できません

重複を削除する

上の図から、重複排除とは同じレイヤーに出現した要素の重複排除を指すことがわかりますが、質問の意味に従って配列を並べ替えることができないため、使用した重複排除ロジックは使用できません(Combined Sum II (バックトラッキング、重複排除) - CSDN ブログ)、重複排除方法を再設計する必要があります。

ここでバックトラッキング方法を考慮しない場合、重複した要素を持つ配列 nums をどのように重複排除できるでしょうか。

図に示すように、セット コレクションを使用して、走査された要素を保存します。新しい要素を走査するたびに、セットを検索して、現在走査されている要素がセット内に出現しました。現在走査されている要素がセット内に見つかった場合、その要素はすでに出現している、つまり前の要素の複製であることを意味します。

走査された要素を保存するために set を使用するのはなぜですか?なぜなら、set データ構造には当然、繰り返しの要素を格納できないためです。

 

他のデータ構造を使用して、走査された要素を保存できますか?

もちろんこの質問にはそれが必要です-100 <= nums[i] <= 100,因此我们完全可以开一个大小为201的数组用于对已经遍历过的元素打上标记,用于标志该元素已经被遍历过

したがって、上記のアイデアを上図のバックトラッキング方式の単層重複排除ロジックに統合すると、この問題の重複排除を完了できます。全体的なコードは次のとおりです

コード

解決策 1

class Solution {
private:
    vector<int> path;
    vector<vector<int>> res;
public:
    void backing(vector<int>& nums,int startIndex)
    {
        if(path.size()>1)
            res.push_back(path);
        
        unordered_set<int> uset;//记录本层元素是否重复
        for(int i=startIndex;i<nums.size();i++)
        {
            /*
            判断当前元素
                1.如果nums[i]<path.back(),说明若加入元素就会使得序列非递增
                2.如果uset.find(nums[i])!=uset.end(),说明当前元素之前在同一层已经出现过
            */
            if((!path.empty() && nums[i]<path.back())
             || uset.find(nums[i])!=uset.end())
                continue;
            
            uset.insert(nums[i]);//记录当前已经使用过的元素
            path.push_back(nums[i]);//遍历路径上的节点
            backing(nums,i+1);
            path.pop_back();//回溯
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backing(nums,0);
        return res;
    }
};

解決策 2

class Solution {
private:
    vector<int> path;//保存当前结果
    vector<vector<int>> res;//保存最终结果
public:
    void backing(vector<int>& nums,int startIndex)
    {
        if(path.size()>1)
            res.push_back(path);
        
        // unordered_set<int> uset;//记录本层元素是否重复
        int used[201]={0};
        for(int i=startIndex;i<nums.size();i++)
        {
            if((!path.empty() && nums[i]<path.back())
             || used[nums[i]+100])
                continue;
            
            // uset.insert(nums[i]);//记录当前已经使用过的元素
            used[nums[i]+100]=1;
            path.push_back(nums[i]);//遍历路径上的节点
            backing(nums,i+1);
            path.pop_back();//回溯
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backing(nums,0);
        return res;
    }
};

おすすめ

転載: blog.csdn.net/qq_58158950/article/details/134799894