研究ノート:デュアルポインターアルゴリズム

ダブルポインタとは、オブジェクトをトラバースするプロセスで、アクセスに単一のポインタを使用する代わりに、同じ方向(高速ポインタと低速ポインタ)または反対方向(衝突ポインタ)の2つのポインタを使用してスキャンすることを指します。対応する目的。

例:
AcWing799。最長の連続した非反復サブシーケンス

長さnの整数列が与えられた場合、繰り返される数値を含まない最長の連続区間を見つけて、その長さを出力します。

方法:
配列visを開いて、区間[i、j]に現れた数を記録します。iが前に進むと、visが見つかった場合は区間vis [a [i]] ++にa [i]を追加します。 [a [i]]> 1、つまり、区間内でのa [i]の出現数が1より大きい場合(つまり、繰り返される数がある場合)、左ポインターjが後方に移動し、 vis [a [j]]-、jが1つ戻ると、jが指すa [j]は、vis [a [i]] == 1になるまで、区間[j、i]に存在しなくなり、jは停止します。移動、この時点でansを更新し、間隔の最大長を記録します

const int N = 1e5+5;

int n,a[N],vis[N];

int main()
{
    
    
	cin>>n;
	for(int i=1;i<=n;i++)	cin>>a[i];
	int ans=0;
	for(int i=1,j=1;i<=n;i++)
	{
    
    
		vis[a[i]]++;
		while(vis[a[i]]>1)	vis[a[j++]]--;//等价于vis[a[j]]--,j++;
		ans=max(ans,i-j+1);
	}
	cout<<ans<<endl;
	return 0;
}

例:
AcWing800。配列要素のターゲット合計

昇順でソートされた2つの順序付けられた配列AとB、およびターゲット値xが与えられます。配列インデックスは0から始まります。
A [i] + B [j] = xを満たす数のペア(i、j)を見つけてください。

データには独自のソリューションが保証されています。

練習:
問題は、配列が昇順で配置されるようにすることです。この単調性は、二重ポインターを使用して使用できます。ポインターiはA配列の先頭を指し、ポインターjはBの末尾を指します。配列を作成し、チェックを開始します。a[i] + b [j]> xの場合、配列の単調性のため、jはj--; a [i] + b [j] <xの場合は前方に移動する必要があります。 、同じ、私は1つ後ろに移動する必要があります、i ++; a [i] + b [j] == xの場合、(i、j)を出力して中断できます

const int N = 1e5+5;

int n,m,x,b[N],a[N];

int main()
{
    
    
	cin>>n>>m>>x;
	for(int i=0;i<n;i++)	cin>>a[i];
	for(int i=0;i<m;i++)	cin>>b[i];
    for(int i=0,j=m-1;i<n;i++)
	{
    
    
	    while(j>=0&&a[i]+b[j]>x)    j--;
	    if(a[i]+b[j]==x)
	    {
    
    
	        cout<<i<<" "<<j<<endl;
	        break;
	    }
	}
	return 0;
}

次のように書くこともできます。

const int N = 1e5+5;

int n,m,x,b[N],a[N];

int main()
{
    
    
	cin>>n>>m>>x;
	for(int i=0;i<n;i++)	cin>>a[i];
	for(int i=0;i<m;i++)	cin>>b[i];
	int i=0,j=m-1;
	while(i<n&&j>=0)
	{
    
    
		if(a[i]+b[j]==x)	break;
		else if(a[i]+b[j]>x)	j--;
		else	if(a[i]+b[j]<x)	i++;
	}
	cout<<i<<" "<<j<<endl;
	return 0;
}

例:
AcWing2816 サブシーケンスを判断する

長さnの整数a1、a2、...、anのシーケンス、および長さmの整数b1、b2、...、bmのシーケンスが与えられます。

シーケンスがbシーケンスのサブシーケンスであるかどうかを判断してください。

サブシーケンスとは、アイテムの一部を元の順序で並べて得られたシーケンスのことです。たとえば、シーケンス{a1、a3、a5}は、シーケンス{a1、a2、a3、a4、a5}のサブシーケンスです。

方法:
aがbのサブシーケンスであるかどうかを判別する必要があるため、ポインターiを配列の先頭を指すように設定し、ポインターjをb配列の先頭を指すように設定してから、b配列
をトラバースできます。 、現在のa [i]がb [j]と同じであるかどうかを判断するたびに、a [i] == b [j]の場合、i ++;
最後のトラバースの後、iがnに等しいかどうかを判断します等しい場合は、配列内の各番号がb配列内で順番に並んでいる可能性があることを意味します。見つかった場合は「はい」を出力し、そうでない場合は「いいえ」を出力します。

const int maxn = 1e5+5;

int n,m;
int a[maxn],b[maxn];

int main()
{
    
    
	cin>>n>>m;
	
	for(int i=0;i<n;i++)	cin>>a[i];
	for(int i=0;i<m;i++)	cin>>b[i];
	
	int i=0,j=0;
	while(i<n&&j<m)
	{
    
    
		if(a[i]==b[j])	i++;
		j++;
	}
	if(i==n)	cout<<"Yes"<<endl;
	else	cout<<"No"<<endl;
	return 0;
}

おすすめ

転載: blog.csdn.net/m0_50815157/article/details/113471130