Zeigen, dass Intervall-Summen-Abfragen in einem binären Array nicht mit linearem Raum und konstanter Zeit durchgeführt werden können

8

Sie erhalten ein großes binäres Array.n

Ich möchte zeigen, dass kein Algorithmus Folgendes kann (oder überrascht sein und herausfinden, dass es solche Algorithmen schließlich gibt):

1) Verarbeiten Sie das Eingabearray mit unbegrenzter Zeit, jedoch nur mit -Bits .O(n)

2) Beantworten Sie Abfragen in konstanter Zeit, wobei die Abfrage nach der Anzahl der gesetzten Bits zwischen Index und Index im Array fragt .x y(x,y)xy

Es scheint, dass die konstante Zeit pro Abfrage dem Algorithmus nicht erlauben sollte, genügend Informationen zu lesen, um die Anzahl der gesetzten Bits zu berechnen.

Wie können wir beweisen, dass es keinen solchen Algorithmus gibt?

Eine allgemeinere Frage wäre:

Welche Untergrenze für die Abfragezeit können wir ableiten , da der Algorithmus -Raum verwenden darf?f(n)

Wenn wir Speicherplatz haben, können wir natürlich alle Teilsummen speichern und Abfragen in beantworten , aber was ist, wenn kleiner ist?O ( 1 ) ff=Ω(nlogn)O(1)f


Sie können annehmen, dass die Größe eines Speicherworts und wir die Indizes in konstanter Zeit lesen können .x , yΘ(logn)x,y

RB
quelle
@ EmilJeřábek - Ich möchte, dass der Algorithmus Bits (linear in der Eingabegröße) verwendet, nicht Speicherwörter. Macht es Sinn? O ( n )O(n)O(n)
RB
2
Ich verstehe, danke für die Klarstellung. Nun noch eine Frage: Welche Operationen können Sie in konstanter Zeit mit Speicherwörtern ausführen? Hier ist ein Kandidatenalgorithmus: Teilen Sie das Array in Blöcke der Größe und speichern Sie für jeden Block den Inhalt von als ein Wort und die Anzahl der gesetzten Bits vor als ein anderes Wort. Dies ergibt Bits. Jede Abfrage kann durch Untersuchen von vier Wörtern beantwortet werden, und sie kann unter Verwendung von -Operationen für diese Wörter wie Verschiebungen, Subtraktion und (am wichtigsten) Bevölkerungszahl berechnet werden . Erlaubt Ihr Modell dies? b b b O ( n ) O ( 1 )(logn)bbbO(n)O(1)
Emil Jeřábek
@ EmilJeřábek - Ich hatte nur arithmetische Operationen, Indizierungen und Bit-Lookups im Sinn (dh ein bestimmtes Bit aus einem Wort herauszuschauen). Standardbitoperationen wie Verschiebungen können ebenfalls berücksichtigt werden. Ich bin damit einverstanden, dass Ihr Algorithmus das Problem tatsächlich löst , wenn wir die Anzahl der gesetzten Bits in zählen könnten . O(1)
RB
Das Problem ergibt sich aus einem Algorithmus, den wir für Intervall-Summen-Abfragen über Schiebefenster erstellen. Das heißt, wir haben einen Strom von ganzen Zahlen, jede in und wir möchten die Summe eines gegebenen Intervalls approximieren. Unser Problem reduziert sich dann auf die exakte Intervallanzahl auf einem (viel kleineren) binären Array (das auch "Folien"). Für ein binäres Schiebefenster mit Größe verwenden wir -Bits , fügen ein Bit in der amortisierten konstanten Zeit hinzu und führen Abfragen in . Ich habe mich gefragt, ob konstante Zeitabfragen möglich sind, auch wenn das Array nicht aktualisiert wird. n O ( n ) O ( log n )0,1,,RnO(n)O(logn)
RB
@ EmilJeřábek - danke für deinen Vorschlag und deine Analyse! Dies kann eine Antwort auf die Frage sein, auch wenn sie unsere Bedürfnisse nicht vollständig erfüllt. Der -Bit-Raum ist für uns eine harte Einschränkung, und wir möchten zeigen, dass kein Algorithmus wie dieser Algorithmus Anfragen in konstanter Zeit beantworten kann. O(n)
RB

Antworten:

6

Ich glaube, dass Sie nach einer kompakten Datenstruktur suchen, die die Rangoperation unterstützt. Sehen...

https://en.m.wikipedia.org/wiki/Succinct_data_structure

Insbesondere können Sie die Emils (erste) Lösung ändern, um die Pop-Count-Operation zu entfernen und durch eine Nachschlagetabelle zu ersetzen (Details finden Sie im Wiki-Artikel). Durch Reduzieren der Größe eines Blocks auf (log n) / 2 Bits verwendet die Nachschlagetabelle o (n) Bits.

Benjamin Sach
quelle
(* facepalm *) Nachschlagetabelle natürlich. Warum habe ich nicht daran gedacht?
Emil Jeřábek
In Anbetracht des obigen Kommentars des OP ist anzumerken, dass die Struktur leicht als Schiebefenster implementiert werden kann, so dass das Verschieben des Fensters um ein Bit (oder sogar einen Block) ebenfalls konstante Zeit in Anspruch nimmt.
Emil Jeřábek
@ EmilJeřábek - Die Übersetzung Ihrer Lösung in die Schiebefenstereinstellung ist nicht einfach. Anstatt die Anzahl der gesetzten Bits im gesamten Array-Teil zu zählen, der dem aktuellen Block vorausgeht, müssen wir die Anzahl der gesetzten Bits innerhalb des Schiebefensters zählen , das diesem Block vorausgeht, was in konstanter Zeit nicht machbar zu sein scheint. Vermisse ich etwas
RB
Nein, das musst du nicht tun. Da Sie letztendlich die Anzahl für von der Anzahl für subtrahieren , spielt es keine Rolle, ob alle gespeicherten Zählungen um einen festen Betrag verschoben sind. Mit anderen Worten, dem linken Rand des Schiebefensters kann eine beliebige Anzahl zugewiesen werden. Wenn Sie das Fenster verschieben, müssen Sie daher nur die Anzahl der Blöcke aktualisieren, in denen sich das neue Element befindet. Von Zeit zu Zeit müssen Sie alle Zählungen reduzieren, damit sie nicht zu viel Platz beanspruchen. Diese kleine Arbeit kann jedoch einfach verteilt werden, sodass pro Abfrage nur O (1) Zeit benötigt wird. yxy
Emil Jeřábek
Tatsächlich kann das Ärgernis im letzten Satz insgesamt elegant vermieden werden, indem alle Zählungen modulo mit einer festen Zahl größer als berechnet werden . n
Emil Jeřábek
6

Ich wäre mir nicht so sicher, ob es einen solchen Algorithmus nicht gibt. Es gibt sicherlich Algorithmen, die sehr nahe kommen. Unten ist , ist , ist , iterierter Logarithmus , und ist .lognlog2nlog(k)nloglogk timesnlognO~(t(n))O(t(n)polylog(t(n)))

Proposition: Es gibt Algorithmen, die erreichen

  1. Raum und Abfragezeit für jede Konstante ;O(nlog(k)n)O(1)k

  2. Leerzeichen und Abfragezeit .O(n)O~(logn)

Die Algorithmen arbeiten wie folgt. Es gibt Parameter und Abhängigkeit von . Wir spalten die Size- Eingangs Array in Size- Blöcke (Stufe 1); Wir teilen jeden Block der Ebene 1 in Blöcke der Größe (Ebene 2) auf. und so weiter bis Level . (Stellen wir uns vor, alle sind Potenzen von , um Probleme mit der Teilbarkeit zu vermeiden.) Dann:k>0n=b0>b1>>bk>0nb0b1b2kbi2

  • Für jedes und jeden Level- Block speichern wir die Anzahl der gesetzten Bits im Intervall vom Beginn des Blocks bis zur nächsten Level- -Blockgrenze .i=1,,ki(i1)

  • Um eine Abfrage aufzulösen, addieren wir die gespeicherten Zahlen, die dem Index entsprechen, und zählen die gesetzten Bits vor dem Index in seinem Level- Block. Wir machen das alles für und getrennt und subtrahieren die Ergebnisse.kkxy

(Wenn die Parameter nicht einfach zu berechnen sind, können wir sie auch speichern.)bi

Diese Anordnung verwendet den Raum und die Abfragezeit

ni=1klogbi1bi,
O(k+bk).

In dem Satz für 1. lassen wir konstant sein und setzen für , .kbi=log(i)n0<i<kbk=1

Für 2. können wir und Der Raum wird dann durch ungefähr für eine Konstante .k=logn

bi=i(logi)3log(i)n.
ni=1klog(i)n+2logii(logi)3log(i)nni=13i(logi)2=cn
c
Emil Jeřábek
quelle
2

Es stellt sich heraus, dass dies nicht nur in Speicherbits möglich ist, wie in Benjamin Sachs Antwort vorgeschlagen, sondern auch in Bits.n ( 1 + o ( 1 ) )O(n)n(1+o(1))

Die Idee ist, sich die Bit-Eingabe als den charakteristischen Vektor einer Teilmenge von (dh das Bit wird gesetzt, wenn in der Menge ist). Dann können wir einfach ein prägnantes Wörterbuch verwenden , um die Menge mit der erforderlichen Anzahl von Bits darzustellen.{ 1 , 2 , , n } i ' t h in{1,2,,n}ithi

RB
quelle