AcWing1532。コインを探す[デュアルポインターアルゴリズムの詳細な説明]

トピック

エヴァは宇宙全体からコインを集めるのが好きです。

ある日、彼女は宇宙のショッピングモールに買い物に行き、チェックアウト時にさまざまなコインを使って支払うことができました。

ただし、特別な支払い要件があります。請求書ごとに、消費量を正確に支払うために使用できるコインは2枚だけです。

彼女が持っているすべてのコインの金種を考えると、彼女が与えられた金額を支払うために2つのコインを見つけることができるかどうかを彼女が判断するのを手伝ってください。

入力形式
最初の行には、コインの数と支払われる金額をそれぞれ表す2つの整数NとMが含まれています。

2行目には、各コインの金種を表すN個の整数が含まれています。

出力形式
V1≤V2およびV1 + V2 = Mとなるように、選択した2つのコインの金種を表す2つの整数V1、V2を含む1行を出力します

答えが一意でない場合は、V1が最小の解が出力されます。

解決策がない場合は、「解決策なし」を出力します。

データ範囲
1≤N≤105、
1≤M≤1000
入力例1:
8 15
1 2 8 7 2 4 11 15
出力例1:
4 11
入力例2:
7 14
1 8 2 7 4 11 15
出力サンプル2:
解決策はありません

デュアルポインタアルゴリズムとは何ですか?

はじめに
デュアルポインタアルゴリズムは広く使用されており、通常のブルートフォース検索と比較して、組み合わせアイテムの順序を修正し、一部の組み合わせオプションを直接除外するため、より効率的なアルゴリズムとして使用できます。考え方は、2つのポインターのそれぞれ、1つのポインターがループを担当し、もう1つのポインターが条件のチェックと協調を担当するというものです。
テンプレート

for (int i = 0, j = 0; i < n; i ++ )
{
    
    
    while (j < i && check(i, j)) j ++ ;

    // 具体问题的逻辑
}
常见问题分类:
    (1) 对于一个序列,用两个指针维护一段区间
    (2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作

使用条件は?

2ポインターアルゴリズムを使用できる場合、それは激しく解決できます。まず、暴力的な解決策を考え出し、次に2ポインターアルゴリズムを使用して最適化することを検討します。デュアルポインタを使用して間隔を維持できる場合、この間隔は単調である必要があります単調性が満たされている場合にのみ、組み合わせアイテムの順序を修正し、他の組み合わせオプションを直接除外できるためです。

問題解決のアイデア

この問題については、最初に暴力的な解決策を考え出します。

for (int i = 0; i < n; i++)
{
    
    
	for (int j = 0; j < i; j++)
	{
    
    
		if (a[i] + a[j] == m) //更新答案
		{
    
    
		
		}
	}
}

時間の複雑さはO(n^2)非常に簡単です。

デュアルポインタアルゴリズムの最適化を検討する

それを作るために最初の配列をソート整然とした

次に、2つのポインタを定義しiji配列の先頭をポイントし、配列jの末尾をポイントします。
ここに画像の説明を挿入

2つのポインタが交差せず、a[i]+a[j]>m説明a[j]が大きくなると、左側のjポインタに移動するため、2つの数a[i] +a[j]が減ります。ループを終了するwhile (i<j&&a[i] + a[j]>m) j--;までのその実行a[i]+a[j]<=m

次に、判断a[i] +a[j]はに等しくなります。m説明a[i]が小さくなった場合と等しくない場合はi、ポインタを移動して、2つの数値a[i] +a[j]が増加するようにします。

上記の操作まで続けてa[i] +a[j] ==m、回答を記録します。

	sort(a, a + n);
	for (int i = 0, j = n - 1; i < j; i++)
	{
    
    
		while (i<j&&a[i] + a[j]>m) j--;
		if (i < j&&a[i] + a[j] == m)
		{
    
    
			//记录答案
		}
	}

以来、iポインタまたはjポインタが一方向に移動することができるi++か、j--最も実行n回数を、時間複雑ですO(n)

完全なコード

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int main()
{
    
    
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < n; i++) cin >> a[i];
	int v1, v2, flag = 0;
	sort(a, a + n);
	for (int i = 0, j = n - 1; i < j; i++)
	{
    
    
		while (i<j&&a[i] + a[j]>m) j--;
		if (i < j&&a[i] + a[j] == m)
		{
    
    
			v1 = a[i];
			v2 = a[j];
			flag = 1;
			break;
		}
	}
	if (flag) cout << v1 << ' ' << v2 << endl;
	else cout << "No Solution" << endl;
	return 0;
}

おすすめ

転載: blog.csdn.net/weixin_45629285/article/details/112802387