Likou 1004スライディングウィンドウ超詳細回答(再現)

  1. 連続する1の最大数III
    複数の0と1で構成される配列Aが与えられた場合、K値を最大で0から1に変更できます。
    1のみを含む最長の(連続した)サブ配列の長さを返します。

    ここに画像の説明を挿入

問題解決のアイデア
最初に、この問題の最も直感的で単純なアイデアを検討してください:各部分文字列を列挙し、その有効性を1つずつ確認し、最大値を更新します。
このアプローチの時間計算量はO(n ^ 3)です。このデータスケールの下では、間違いなく
タイムアウトになります。タイムアウトの理由は検証計算が何度も繰り返され、意味のない文字列が多数列挙されているためです。
最も価値のある問題での経験に基づいています。このような連続した部分配列の性質上、ダブルポインター(スライディングウィンドウ)を使用することは非常に良い考えです

ダブルポインタソリューションダブルポインタソリューション
の焦点は、2つのポインタを維持することです。2
つのポインタ(配列の添え字値として表される)を設定し、左側のポインタは現在の部分文字列の左側の境界を指し、右側のポインタはの右側の境界を指します。現在の部分文字列。特定の方法を採用します。左右のポインタ間の現在の部分文字列が要件を満たすようにします。つまり、「0」の数がK以下になります。
また、最長の文字列が必要であることを簡単に知ることができます文字列に表示され、「0」の数が飽和している(「0」が多い場合)または最大(Kが比較的大きい場合)であるため、右ポインタをできるだけ右に移動する必要があります

では、左のポインタが固定されている場合、どのような状況で右のポインタを右に移動できますか?
変換数Kが残っているか
、右ポインタの次のビットが「1」です。
右ポインタを移動すると、各左ポインタに対応する最長の有効な文字列と、が指す要素の次のビットを見つけることができます。右ポインタは「0」である必要があります。
次に、各配列要素を左ポインタとして使用し、上記の方法で最長の有効な文字列を列挙して、結果を返すことができます。

しかし、それでも十分な速さではありません

計算速度が足りないのは、計算を繰り返すためです。左ポインタが変わると、右ポインタが左ポインタから右に動き始めます。前の操作の結果が有効に活用されないため、不要な操作が多くなります。 。
では、繰り返し計算を回避する方法は?

私たちの鍵は、今述べた「0数飽和」にあります
。これは最長の文字列になる可能性があり、その中の「0」の数は飽和または最大でなければなりません。
次に何らかの操作を使用して、左ポインターを右に移動できますその後、新しい左ポインタに対応する「0」番号の飽和文字列/「0」番号の最大文字列をすぐに取得できます。

まず、左のポインタが1ビット右に移動する状況を調べてみましょう。
まず、事実を明確にする必要があります。右のポインタが文字列の末尾に達したときに、左のポインタが移動し続ける必要はありません。右、左ポインタが右に移動すると部分文字列の長さが確実に短くなるためです。これは小さく、飽和プロパティは保証できません。
つまり、左ポインタが右に移動するための条件は次のとおりです。ポインタが文字列の右の境界に触れていない
場合、推論が得られます。左のポインタを右に移動する必要がある場合、文字列の「0」は最大ではなく飽和している必要があります(「飽和」とは部分文字列の0の数がKに等しく、0から1に変換できないこと。「最大」は、文字列全体のすべての0が1に変換されたことを意味します。飽和しており、最大の場合は右に移動する必要はありません。

この推論により、左のポインタが右に移動したときの状況を考えることができます。

現在の左ポインタが指す要素が「0」の場合:左ポインタが右に移動すると、部分文字列の「0」の数が1つ減ります。飽和特性を維持するために、前述のとおりです。 「右ポインタが指す要素の次のビットは「0」でなければなりません」ので、右ポインタを少なくとも1ビット右に移動する必要があります(右移動後の次のビットが「1」の場合、あなたは)右に移動し続けることができます
「1」である要素は左ポインタで指さとき:右にシフトするとするとき、左ポインタ、ストリングで「0」の数は変わらず、我々はの飽和特性を維持するので。各部分文字列、右ポインタは右に移動できません
。各左ポインタの移動とそれに続く右ポインタの移動の一連の操作の後、更新されます。最大値
上記の操作を通じて、右ポインタが配列の右境界に接触するまでトラバースします。、および修飾された文字列のグローバル最大長を取得できます

著者:
amachi -inoriリンク:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/c-1004-hua-dong-chuang-kou-chao-xiang-xi-jie-shuo -/
ソース:LeetCode
ここに画像の説明を挿入

//天知いのり 2020.5.24
class Solution {
    
    
public:
    int longestOnes(vector<int>& A, int K) {
    
    
        int left(0), right(0);
        int max(0);
        while (left <= right && right < A.size()) {
    
    
            while (right < A.size() && (A[right] || K != 0)) {
    
    
                if (!A[right]) K--;
                right++;
            }
            max = std::max(right - left, max);
            if (A[left]) left++;
            else left++, right++;
        }
        return max;
    }
};

作者:amachi-inori
链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/c-1004-hua-dong-chuang-kou-chao-xiang-xi-jie-shuo-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

私の解決策

class Solution {
    
    
public:
	int longestOnes(vector<int>& A, int K) {
    
    
		int len = A.size();
		int left = 0, right = 0;//窗体起始点&最终点下一个位置
		int max_lenth = 0;
		int cur_lenth = 0;
		int nums = 0;//记录0的个数
		while (left <= right && right < len) {
    
    
			while (right < len &&(nums < K || A[right]) ) {
    
    //当窗体内0的个数小于K的时候就扩增窗体
				if (A[right] == 0)
					nums++;
				right++;
			}
			//出循环之后此时窗体内0的数目为K
			cur_lenth = right - left;//当前窗口的大小
			if (cur_lenth > max_lenth)
				max_lenth = cur_lenth;
			if (!A[left])
				left++, right++;//当窗口最左端为0,右移之后又可以继续向左扩大窗口
			else
				left++;//若最左边是1,那么移动之后会少一个1,右侧暂且不动
		}
		return max_lenth;
	}
};

おすすめ

転載: blog.csdn.net/Genius_bin/article/details/113446625