AcWing 1532. Finden Sie Münzen [Detaillierte Erklärung des Dual-Pointer-Algorithmus]

Thema

Eva sammelt gerne Münzen aus dem gesamten Universum.

Eines Tages ging sie in ein Einkaufszentrum im Universum, um einzukaufen, und sie konnte verschiedene Münzen verwenden, um an der Kasse zu bezahlen.

Es gibt jedoch eine spezielle Zahlungsanforderung: Für jede Rechnung kann sie nur genau zwei Münzen verwenden, um den Verbrauchsbetrag genau zu bezahlen.

Bitte helfen Sie ihr angesichts der Stückelung aller Münzen, festzustellen, ob sie zwei Münzen finden kann, um den angegebenen Betrag zu bezahlen.

Eingabeformat Die
erste Zeile enthält zwei Ganzzahlen N und M, die jeweils die Anzahl der Münzen und den zu zahlenden Betrag darstellen.

Die zweite Zeile enthält N Ganzzahlen, die den Nennwert jeder Münze darstellen.

Ausgabeformat
Geben Sie eine Zeile aus, die zwei Ganzzahlen V1, V2 enthält, die die Nennwerte der beiden ausgewählten Münzen darstellen, sodass V1 ≤ V2 und V1 + V2 = M.

Wenn die Antwort nicht eindeutig ist, wird die Lösung mit der kleinsten V1 ausgegeben.

Wenn es keine Lösung gibt, geben Sie No Solution aus.

Datenbereich
1
N 105,
1M 1000 Eingabebeispiel 1:
8 15
1 2 8 7 2 4 11 15
Ausgabebeispiel 1:
4 11
Eingabebeispiel 2:
7 14
1 8 7 2 4 11 15
Ausgabebeispiel 2:
Keine Lösung

Was ist ein Dual-Pointer-Algorithmus?

Einführung Der
Dual-Pointer-Algorithmus ist weit verbreitet und kann als effizienterer Algorithmus verwendet werden, da er eine bestimmte Reihenfolge für Kombinationselemente festlegt und einige Kombinationsoptionen im Vergleich zur normalen Brute-Force-Suche direkt ausschließt. Die Idee ist, dass jeder der beiden Zeiger, ein Zeiger für die Schleife und der andere Zeiger für die Überprüfung der Bedingungen und die Zusammenarbeit verantwortlich ist.
Vorlage

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

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

Was sind die Nutzungsbedingungen?

Wo der Zwei-Zeiger-Algorithmus verwendet werden kann, kann er gewaltsam gelöst werden. Wir haben zuerst eine gewalttätige Lösung gefunden und erwägen dann, den Zwei-Zeiger-Algorithmus zur Optimierung zu verwenden. Wenn zwei Zeiger zum Aufrechterhalten eines Intervalls verwendet werden können, muss dieses Intervall monoton sein . Denn nur wenn die Monotonie erfüllt ist, können wir eine Reihenfolge für die Kombinationselemente festlegen und andere Kombinationsoptionen direkt ausschließen.

Ideen zur Problemlösung

Überlegen Sie sich für dieses Problem zunächst eine gewalttätige Lösung.

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

Die zeitliche Komplexität ist O(n^2)sehr einfach.

Betrachten Sie die Optimierung des Dual-Pointer-Algorithmus

Sortieren Sie das Array zuerst, um es ordentlich zu machen .

Dann definieren zwei Zeiger i, j. iZeigen Sie auf den Anfang des Arrays, jzeigen Sie auf das Ende des Arrays.
Fügen Sie hier eine Bildbeschreibung ein

Wenn sich die beiden Zeiger nicht schneiden und die a[i]+a[j]>mBeschreibung a[j]groß ist, bewegt sie sich zum linken jZeiger, und die Anzahl von zwei a[i] +a[j]wird verringert. Diese Ausführung while (i<j&&a[i] + a[j]>m) j--;bis zum a[i]+a[j]<=mVerlassen der Schleife.

Dann ist die Beurteilung a[i] +a[j]gleich m, wenn nicht gleich der Beschreibung, a[i]die kleiner genommen wird, bewegen Sie iden Zeiger, so dass zwei Zahlen a[i] +a[j]zunehmen.

Fahren Sie fort, bis die obige Operation ausgeführt a[i] +a[j] ==mist. Wir zeichnen die Antworten auf.

	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)
		{
    
    
			//记录答案
		}
	}

Da der iZeiger oder die jZeiger in eine Richtung bewegt werden können i++oder j--am häufigsten ausgeführt werden n, ist die Zeitkomplexität O(n).

Vollständiger Code

#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;
}

Ich denke du magst

Origin blog.csdn.net/weixin_45629285/article/details/112802387
Empfohlen
Rangfolge