Wie erhalte ich den Schnittpunkt zwischen zwei Arrays als neues Array?

70

Ich war in verschiedenen Situationen oft mit diesem Problem konfrontiert. Es ist generisch für alle Programmiersprachen, obwohl ich mit C oder Java vertraut bin.

Betrachten wir zwei Arrays (oder Sammlungen):

char[] A = {'a', 'b', 'c', 'd'};
char[] B = {'c', 'd', 'e', 'f'};

Wie erhalte ich die gemeinsamen Elemente zwischen den beiden Arrays als neues Array? In diesem Fall ist der Schnittpunkt der Arrays A und B char[] c = {'c', 'd'}.

Ich möchte die wiederholte Iteration eines Arrays innerhalb des anderen Arrays vermeiden, die die Ausführungszeit um (Länge von A mal Länge von B) erhöht, was bei großen Arrays zu viel ist.

Gibt es eine Möglichkeit, einen einzelnen Durchgang in jedem Array durchzuführen, um die gemeinsamen Elemente zu erhalten?

Ranjan Sarma
quelle
23
Sortieren Sie zuerst die Arrays. Dann brauchen Sie nur noch einen Durchgang.
Daniel Fischer
51
Verwenden Sie HashSet, um alle Daten aus dem ersten Array zu speichern. Überprüfen Sie dann für jedes Element im zweiten Array, ob das HashSet das Element enthält (). Die Komplexität der Sortierung ist O (n lg n), während die Komplexität dieser Methode O (n) ist
user1700184
4
Was ist dir wichtiger? Zeit- oder Raumeffizienz?
Jakub Zaverka
1
Ist der Typ der Arrays tatsächlich char? Einige der Argumente in den Kommentaren unten könnten gelöst werden, indem die Typen eingeschränkt werden. Zum Beispiel geht alles, was O(N)mit Hash-Tabellen zu erwarten ist, aus dem Fenster, wenn Sie keine vernünftige Hash-Funktion für den Typ haben (aus diesem Grund empfiehlt Java, eine zu schreiben). Umgekehrt könnte bei einer charausreichend großen Eingabe am schnellsten ein Array mit einem Element für jeden Zeichenwert (im Allgemeinen 256 oder 65536) erstellt und damit aufgezeichnet werden, welche Zeichen in jeder Eingabe erscheinen.
Steve Jessop
24
Ohne eine klare Definition dessen, was "am besten" ist, schlage ich diese Lösung zum Sortieren von Arrays vor: Drucken Sie jedes Array-Element auf einen Zettel und legen Sie jeden Zettel in einen deutlich gekennzeichneten Umschlag. Senden Sie die Umschläge an Ihre Großmutter mit der Anweisung, nur die in beiden Umschlägen enthaltenen Artikel zusammen mit einigen Keksen zurückzugeben. Die Lösung ist nicht sehr schnell O(USPS^grandmother), aber am besten, weil Cookies fantastisch sind.
zzzzBov

Antworten:

12

Da dies für mich wie ein String-Algorithmus aussieht, gehe ich für einen Moment davon aus, dass es nicht möglich ist, diese Sequenz (daher String) zu sortieren. Dann können Sie den Longest Common Sequence-Algorithmus (LCS) verwenden.

Unter der Annahme, dass die Eingabegröße konstant ist, hat das Problem eine Komplexität von O (nxm) (Länge der beiden Eingaben).

Moataz Elmasry
quelle
1
Aber warum eine tun O(n*m)komplizierte Lösung , wenn es O(n+m)und O(nlog(m))welche? : |
Amit
1
Wie wird LCS einen Schnittpunkt von 2 Strings ergeben? Wir könnten viele Charaktere verpassen. für zB s1 = [ABDCEF] und s2 = [CDEFGH] ist LCS hier [DEF], während der Schnittpunkt von 2 Strings [CDEF] ist! Vermisse ich hier etwas?
srbhkmr
1
srbh.kmr, @Gabriel, ich stimme Ihrem Beispiel nicht zu. Dies ist kein Mangel von LCS, aber von Ihren Beispielen müssen die beiden Eingänge einfach die genaue gemeinsame Reihenfolge teilen, um eine Übereinstimmung zu finden. Normalerweise läuft es von links nach rechts, aber Sie können es in die andere Richtung tun. Der Algorithmus sucht nach der gemeinsamen Sequenz und nur nach den gemeinsamen Zeichen, sodass "eins" höchstens einen Buchstaben mit "eno" übereinstimmt. Dies ist, was der Algorithmus tut und kein Nachteil davon
Moataz Elmasry
2
LCS gibt nicht die richtige Antwort für dieses Problem. Der Algorithmus arbeitet mit Zeichenfolgen, bei denen die Reihenfolge wichtig ist. In diesem Fall befindet sich der Schnittpunkt immer in Mengen, bei denen die Reihenfolge keine Rolle spielt. Das einfache Beispiel von @Gabriel ist genau richtig. Wir benötigen mehr Annahmen zu den Eingabedaten, damit dies funktioniert. Die Hash-Antwort ist angesichts der Bestellbeschränkung wahrscheinlich die beste.
Jace
4
Nun, das OP fragte nach dem Schnittpunkt zwischen den beiden Arrays. Schnittmenge ist ein Konzept aus der Mengenlehre und Mengen (per Definition), die nicht von der Reihenfolge ihrer Elemente abhängen. Ich sage nicht, dass LCS aus irgendeinem Grund schlecht ist. Ich behaupte nur, es gibt Ihnen nicht die Kreuzung. Es ist ein Algorithmus, der ein Problem löst, aber nicht das (gesetzte) Schnittpunktproblem. Wenn die Arrays nicht als Mengen betrachtet werden sollen, dann ok, aber dann fragen Sie wahrscheinlich nicht nach einer echten Schnittmenge. Aber ich verstehe den Punkt Ihrer Annahme: Wenn es sich um ein Array handelt, handelt es sich eher um eine Zeichenfolge als um eine Menge.
Gabriel
108
foreach element e in array A
    insert e into hash table H

foreach element e in array B
    if H contains e 
        print e

Dieser Algorithmus ist O(N)zeitlich und O(N)räumlich.

Um zusätzlichen Platz zu vermeiden, können Sie den sortierungsbasierten Ansatz verwenden.

Codaddict
quelle
5
@Yola Es gibt keine Lösung, die schneller als O (n) ist. es kann nicht geben.
Konrad Rudolph
5
Beachten Sie, dass es immer noch ein Problem mit Duplikaten gibt (wie damit umzugehen ist nicht in der Frage angegeben), aber häufig möchten Sie jedes Element min{#occurances(A),#occurances(B)}oder nur einmal drucken , während diese Lösung sie #occurances(B)mal druckt
Uhr
6
@ Yola Wir können den ganzen Tag Gedichte wachsen. Aber Sie sagten , „nicht der schnellste Weg , “ und das ist falsch in der Praxis (in dem erwarteten Fall es ist die schnellste Lösung) und in der Theorie (wenn es hart auf hart kommt , kann Sie ein Schema implementieren , die entweder macht nicht-lineare Leistungs äußerst unwahrscheinlich oder garantiert sogar lineare Leistung für eine begrenzte Domäne). Keine dieser theoretisch perfekten Lösungen ist in typischen Anwendungsfällen notwendigerweise leicht sicherzustellen, aber Hashing ist bereits die schnellste Lösung für den typischen Anwendungsfall.
Konrad Rudolph
3
@ Yola Nein, die Suche in einer Hash-Tabelle dauert O (1). Wie lange die Berechnung des Hashs dauert, hängt vom Schlüsseltyp ab, ist jedoch normalerweise nicht viel langsamer als der Vergleich zweier Schlüssel (der in einem Baum und beim Sortieren erforderlich ist). Insbesondere für einfache charTasten ist es sehr schnell.
Konrad Rudolph
3
Alles dauert O (1) Zeit, wenn Sie die Größe des Datensatzes begrenzen. Hash-Lookups sind O (1) für Dataset-Größen bis zu einer gewissen Grenze, aber auch das Berücksichtigen von Primzahlen. Hashes sind aufgrund einer kleinen konstanten, nicht großen O-Notation schnell.
Yakk - Adam Nevraumont
33

Die Untergrenze für die Effizienz ist O (n) - Sie müssen mindestens alle Elemente lesen. Dann gibt es mehrere Ansätze:

Dummester einfachster Ansatz

Suchen Sie nach jedem Element aus Array eins in Array zwei. Zeitkomplexität O (n ^ 2).

Sortieransatz

Sie müssen nur Array eins sortieren und dann mithilfe der binären Suche nach Elementen aus Array zwei suchen. Zeitliche Komplexität: Sortieren von O (nlogn), Suchen von O (n * logn) = O (nlogn), Gesamt-O (nlogn).

Hash-Ansatz

Erstellen Sie eine Hash-Tabelle aus Array-One-Elementen. Suchen Sie nach Elementen aus der zweiten Tabelle in der Hash-Tabelle. Die zeitliche Komplexität hängt von der Hash-Funktion ab. Sie können O (1) für Suchvorgänge im optimalen Fall erreichen (alle Elemente haben unterschiedliche Hashwerte), im schlimmsten Fall jedoch O (n) (alle Elemente haben denselben Hashwert). Gesamtzeitkomplexität: O (n ^ x), wobei x ein Faktor für die Effizienz der Hash-Funktion ist (zwischen 1 und 2).

Bei einigen Hash-Funktionen wird garantiert, dass eine Tabelle ohne Kollisionen erstellt wird. Das Gebäude benötigt jedoch nicht mehr für jedes Element streng O (1) Zeit. In den meisten Fällen ist es O (1). Wenn die Tabelle jedoch voll ist oder eine Kollision auftritt, muss die Tabelle erneut aufbereitet werden, wobei O (n) Zeit benötigt wird. Dies passiert nicht so oft, viel seltener als saubere Adds. Die AMORTISIERTE Zeitkomplexität ist also O (1). Es ist uns egal, dass einige der Adds O (n) Zeit benötigen, solange die Mehrheit der Adds O (1) Zeit benötigt.

Trotzdem muss die Tabelle im Extremfall bei jeder einzelnen Einfügung erneut aufgewärmt werden, sodass die strenge zeitliche Komplexität O (n ^ 2) wäre.

Jakub Zaverka
quelle
1
Ein erneutes Aufwärmen ist nicht erforderlich, da die Länge des Arrays vorberechnet werden kann und Sie die Hash-Tabelle mit der Größe erstellen können n * LF^-1, in der LFsich Ihr vordefinierter Ladefaktor befindet. Die Komplexität ist O(1)pro Operation für jede LF < 1und nicht O(n^LF), da die erwartete Anzahl von Lesevorgängen E= 1 + 1*LF + 1*LF^2 + ... + 1*LF^n < CONSTANT(Summe der geometrischen Reihen) ist, also jede Operation O(1). Das heißt, der schlimmste Fall von Hash-Tabellen ist immer noch O(n)pro O(1)
Operation
Es kann auch ein Sortieransatz durchgeführt werden O(NlogM), bei dem N die Länge des längeren Arrays und M die Länge des kürzeren Arrays ist.
Amit
1
@amit Ich stimme zu, aber bei einer Kollision in der Tabelle ist noch eine Aufbereitung erforderlich.
Jakub Zaverka
Wenn Sie von einer Wiederaufbereitungslösung für Kollisionen ausgehen (und nicht von Verkettung oder linearer offener Adressierung), dann ja. Aber es wird ein O(n)durchschnittlicher Fall sein und nicht O(n^LF).
Amit
2
@Konrad Das leugne ich nicht. Ich arbeite nur mit strenger Zeitkomplexität, den Worst-Case-Szenarien.
Jakub Zaverka
20

In einigen Sprachen gibt es einige Methoden, von denen ich weiß, dass sie genau das tun, was Sie wollen. Haben Sie sich überlegt, einige dieser Implementierungen zu betrachten?

PHP - array_intersect ()

$array1 = array("a" => "green", "red", "blue");
$array2 = array("b" => "green", "yellow", "red");
$result = array_intersect($array1, $array2);
print_r($result);

>> green
   red

Java - List.retainAll

Collection listOne = new ArrayList(Arrays.asList("milan","dingo", "elpha", "hafil", "meat", "iga", "neeta.peeta"));
Collection listTwo = new ArrayList(Arrays.asList("hafil", "iga", "binga", "mike", "dingo"));

listOne.retainAll( listTwo );
System.out.println( listOne );

>> dingo, hafil, iga
Mike
quelle
1
Python kann dies auch mit Sets tun . Ich stelle mir vor, dass viele Sprachen auch einen festgelegten Typ haben, der damit umgehen kann.
Thegrinner
Ich kann darauf wetten, dass retainAlleine Arraylist (die gesamte List-Implementierung in std java) ein O (n ^ 2) macht.
st0le
5
    public static void main(String[] args) {
        char[] a = {'a', 'b', 'c', 'd'};
        char[] b = {'c', 'd', 'e', 'f'};
        System.out.println(intersect(a, b));
    }

    private static Set<Character> intersect(char[] a, char[] b) {
        Set<Character> aSet = new HashSet<Character>();
        Set<Character> intersection = new HashSet<Character>();
        for (char c : a) {
            aSet.add(c);
        }
        for (char c : b) {
            if (aSet.contains(c)) {
                intersection.add(c);
            }
        }
        return intersection;
    }
Mik378
quelle
Die Leistung ist etwas weniger als optimal, da Sie den zweiten Satz nicht erstellen müssen, um zu überprüfen, ob er Elemente aus dem zweiten enthält.
Groo
Ich würde auch die Größe überprüfen, wenn b groß und a klein ist, läuft Ihr Code langsamer und überprüft den größeren Satz
Exussum
@ user1281385 In diesem Fall ist der Umgang mit Zeichen contains()unabhängig von der Größe der Menge immer von O (1) -Komplexität .
Mik378
4
int s[256] // for considering all ascii values, serves as a hash function

for(int i=0;i<256;i++)
s[i]=0;

char a[]={'a','b','c','d'};
char b[]={'c','d','e','f'};

for(int i=0;i<sizeof(a);i++)
{
   s[a[i]]++;
 }

 for(int i=0;i<sizeof(b);i++)//checker function
 {
     if(s[b[i]]>0)
       cout<<b[i]; 
  }


  complexity O(m+n);
  m- length of array a
  n- length of array b
Sumit Kumar Saha
quelle
3

Google Guava

Es gibt bereits viele gute Antworten darauf, aber wenn Sie den Einzeiler-Ansatz mit einer Bibliothek für Lazy-Coding verwenden möchten, würde ich mich für Google Guava (für Java) und seine Sets.intersectionMethode entscheiden.

(kein Compiler zur Hand, ertrage es mit mir)

char[] A = {'a', 'b', 'c', 'd'};
char[] B = {'c', 'd', 'e', 'f'};

Set<Character> intersection = Sets.intersection(
    Sets.newHashSet<Character>(Chars.asList(a)),
    Sets.newHashSet<Character>(Chars.asList(b))
);

Dies setzt natürlich voraus, dass beide Arrays keine Duplikate haben. In diesem Fall wäre die Verwendung einer festgelegten Datenstruktur sinnvoller und würde diese Art von Operation effizienter ermöglichen, insbesondere wenn Sie nicht von Anfang an von einem Array von Grundelementen ausgehen .

Kann oder kann nicht zu Ihrem Anwendungsfall passen, aber eine Art Kinderspiel für den allgemeinen Fall.

Haylem
quelle
2
  1. Sortieren Sie beide Arrays.
  2. Führen Sie dann eine Schleife durch, bis sie gemeinsame Elemente haben. Oder eines der Arrays erreicht sein Ende.

Asymptotisch erfordert dies die Komplexität der Sortierung. dh O (NlogN) wobei N die Länge eines längeren Eingabearrays ist.

PP
quelle
5
Es kann verbessert werden O(NlogM)(N ist die Länge des größeren Arra, M ist die kürzere), indem das kürzere Array allein sortiert und jedes Element im längeren Array iterativ + binär durchsucht wird.
Amit
2

Wenn Sie sich für Duplikate interessieren, verwenden Sie eine Hash-Map, um Liste A zu indizieren, wobei der Schlüssel das Element und der Wert die Anzahl der Male ist, die dieses Element gesehen wurde.

Sie durchlaufen das erste und für jedes Element in A und fügen es dort mit dem Wert 1 ein. Wenn es bereits in der Karte vorhanden ist, fügen Sie diesem Wert eins hinzu.

Als nächstes iterieren Sie durch B, und wenn der Wert vorhanden ist, subtrahieren Sie 1. Wenn nicht, geben Sie -1 in den Wert in der Tabelle für dieses Element ein.

Zum Schluss durchlaufen Sie die Karte und drucken für jedes Element mit dem Wert! = 0 als Differenz aus.

private static <T> List<T> intersectArrays(List<T> a, List<T> b) {
    Map<T, Long> intersectionCountMap = new HashMap<T, Long>((((Math.max(a.size(), b.size()))*4)/3)+1);
    List<T> returnList = new LinkedList<T>();
    for(T element : a) {
        Long count = intersectionCountMap.get(element);
        if (count != null) {
            intersectionCountMap.put(element, count+1);
        } else {
            intersectionCountMap.put(element, 1L);
        }
    }
    for (T element : b) {
        Long count = intersectionCountMap.get(element);
        if (count != null) {
            intersectionCountMap.put(element, count-1);
        } else {
            intersectionCountMap.put(element, -1L);
        }            
    }
    for(T key : intersectionCountMap.keySet()) {
        Long count = intersectionCountMap.get(key);
        if (count != null && count != 0) {
            for(long i = 0; i < count; i++) {
                returnList.add(key);
            }
        }
    }
    return returnList;
}

Dies sollte ausgeführt werden O(n), da wir die Listen jeweils nur einmal und die Karte nur einmal wiederholen. Die hier in Java verwendeten Datenstrukturen sollten effizient sein, da sie HashMapmit einer Kapazität aufgebaut sind, die die größte Größe der Listen verarbeiten kann.

Ich verwende a LinkedListfür die Rückgabe, da es uns die Möglichkeit bietet, eine Liste für unsere Kreuzung unbekannter Größe hinzuzufügen und zu durchlaufen.

Nikolaus
quelle
1

Der beste Weg ist, überhaupt nicht mit Arrays zu beginnen. Arrays sind optimal für den wahlfreien Zugriff auf Elemente, aber nicht optimal für die Suche (darum geht es beim Finden der Kreuzung). Wenn Sie über Schnittmengen sprechen , müssen Sie die Arrays als Mengen betrachten. Verwenden Sie daher eine geeignetere Datenstruktur (in Java a Set). Dann ist die Aufgabe viel effizienter.

Raedwald
quelle
1
Hängt davon ab. Für eine kleine Anzahl von Datenpunkten (~ kleiner als 15) Arrays ist die schnellste Datenstruktur für die Suche.
Konrad Rudolph
… Ist übrigens Setin Java eine Schnittstelle und kann durch ein lineares Array implementiert werden.
Konrad Rudolph
1

Sie können einen Baum verwenden, aber die Zeit ist O (n (log n)) und die Elemente müssen vergleichbar sein

Yola
quelle
3
Bäume sind für konstante Daten in Bezug auf Sortierlösungen sehr ineffizient. Der Hauptgrund dafür ist der Cache - Arrays sind VIEL effizienter als Bäume. (Obwohl es O(nlogn)genau wie sortieren und iterieren ist, werden die verborgenen Konstanten viel höher sein)
amit
1

Sortieren Sie zunächst die beiden Arrays mit dem besten Sortieralgorithmus.
Mit der linearen Suche können Sie dann die gemeinsamen Elemente erhalten.

Wenn ein zusätzlicher Speicherplatz bereitgestellt wird, können wir dazu die Hash-Tabelle verwenden.

Kishore
quelle
1

in rubin kann man einfach sagen

a = ['a', 'b', 'c', 'd']
b = ['c', 'd', 'e', 'f']
c = a & b

c enthält ['c', 'd']

Colin MacKenzie - III
quelle
1

Sortieren Sie zuerst zwei Arrays und iterieren Sie sie dann. Wenn sie dasselbe Element sind, fügen Sie sie hinzu, um das Array zurückzugeben.

Code ist hier:

public static void printArr(int[] arr){
    for (int a:arr){
        System.out.print(a + ", ");
    }
    System.out.println();
}

public static int[] intersectionOf(int[] arr1, int[] arr2){
    Arrays.sort(arr1);
    Arrays.sort(arr2);

    printArr(arr1);
    printArr(arr2);

    int i=0, j=0, k=0;
    int[] arr = new int[Math.min(arr1.length, arr2.length)];

    while( i < arr1.length && j < arr2.length){
        if(arr1[i] < arr2[j]){
            i++;
        } else if(arr1[i] > arr2[j]){
            j++;
        } else {
            arr[k++] = arr1[i++];
            j++;
        }
    }
    return Arrays.copyOf(arr, k);
}

public static void main(String[] args) {
    int[] arr1 = {1, 2, 6};
    int[] arr2 = {10, 2, 5, 1};
    printArr(intersectionOf(arr1,arr2));
}

Ausgänge:

arr1: 1, 2, 6, 
arr2: 1, 2, 5, 10, 
arr: 1, 2, 
Alan Dong
quelle
0

Angenommen, Sie haben es mit ANSI-Zeichen zu tun. Der Ansatz sollte für Unicode ähnlich sein, ändern Sie einfach den Bereich.

char[] A = {'a', 'b', 'c', 'd'};
char[] B = {'c', 'd', 'e', 'f'};
int[] charset = new int[256]

for(int i=0; i<A.length; i++) {
  charset[A[i]]++;
}

Durchlaufen Sie nun das B, und Sie können überprüfen, ob der entsprechende Zeichensatzwert für das zu iterierende Zeichen größer als 0 ist. Sie können sie in einer Liste oder einer anderen Sammlung speichern.

Dieser Ansatz berücksichtigt die Komplexität der O (n) -Zeit und einen konstanten Platz für Ihre Überprüfungen, wobei Ihr neues Array / Ihre neue Liste, die zum Speichern der gemeinsamen Elemente verwendet wird, nicht berücksichtigt wird.

Dies ist in Bezug auf die Raumkomplexität besser als der HashSet / Hashtable-Ansatz.

Vamshidhar Behara
quelle
2
Der Bereich von Unicode beträgt (theoretisch) 32 Bit - das würde 16 GiB RAM für Ihre charsetTabelle erfordern . Sehen Sie, warum die Leute stattdessen Hash-Tabellen verwendeten?
Konrad Rudolph
@KonradRudolph Ich denke, es hängt wirklich vom Problem ab und davon, welche Kompromisse man eingehen möchte. Wenn wir Terabyte an Dateien vergleichen möchten, ist eine Zeichensatztabelle mit fester Größe praktikabler, wenn Sie sich an einen Computer halten möchten.
Vamshidhar Behara
@KonradRudolph Der obige Fall übertrifft auch den Hash-Tabellen-Ansatz jederzeit, wenn wir wissen, dass es sich um ASCII-Zeichenfolgen handelt.
Vamshidhar Behara
Träum weiter. Das Unicode-Array wäre 4 GiB groß. Selbst wenn wir über genügend RAM verfügen, würde das Direktzugriffsmuster die Cache-Leistung beeinträchtigen. Eine Hash-Tabelle ist schneller.
Konrad Rudolph
Wäre das Einfügen in eine Hash-Tabelle für große Datenmengen nicht O (n)? Wie wäre es schneller? Ich denke, ein Kartenreduzierungsansatz kann ein besserer Ansatz zur Lösung dieses Problems sein, wenn es um große Datenmengen geht.
Vamshidhar Behara
0

Sie können HashSet in .NET 3.5 oder höher verwenden. Beispiel c # Code:

HashSet<int> set1 = new HashSet<int>(new int[]{8, 12, 13, 15});

HashSet<int> set2 = new HashSet<int>(new int[] { 15, 16, 7, 8, 9 });

set1.IntersectWith(set2);

foreach (int i in set1)

   Console.Write(i+ " ");

// Ausgabe: 8 15

Sanj
quelle
0

Sortieren Sie jetzt eines der Arrays (m Log (m)). Wählen Sie jedes Element aus einem anderen Array aus und führen Sie eine binäre Suche im ersten Array (dem sortierten) durch -> n Log (m)

Gesamtzeitkomplexität: - (n + m) Protokoll (m) .

Navgupta
quelle
0

Ich hoffe, dass das Folgende nützlich wäre. Dies sind zwei verschiedene Ansätze:

  • Einfacher Schnittpunkt, an dem Sie alle Elemente eines Arrays mit einem anderen Array vergleichen.

  • Sortier- und suchbasierter Ansatz, bei dem ein Array sortiert und das zweite Array-Element im ersten Array mithilfe der binären Suche durchsucht wird.

//

public class IntersectionOfUnsortedArrays {
    public static void main(String[] args) {
        int[] arr1 = { 12, 4, 17 };
        int[] arr2 = { 1, 12, 7, 17 };
        System.out.println("Intersection Using Simple Comparision");
        printArray(simpleIntersection(arr1, arr2));
        System.out.println("Intersection Using Sort and Binary Search");
        printArray(sortingBasedIntersection(arr1, arr2));
    }

    /*
     * Simple intersection based on the comparison without any sorting.
     * Complexity O(n^2)
     */
    public static int[] simpleIntersection(int[] a, int[] b) {
        int minlen = a.length > b.length ? b.length : a.length;
        int c[] = new int[minlen];
        int k=0;
        for(int i=0;i<a.length;i++){
            for(int j=0;j<b.length;j++){
                if(a[i]==b[j]){
                    c[k++]=a[i];
                }
            }
        }
        int arr[] = new int[k];
        // copy the final array to remove unwanted 0's from the array c
        System.arraycopy(c, 0, arr, 0, k);
        return arr;
    }

    /*
     * Sorting and Searching based intersection.
     * Complexity Sorting O(n^2) + Searching O(log n)
     */

    public static int[] sortingBasedIntersection(int[] a, int[] b){
        insertionSort(a);
        int minlen = a.length > b.length ? b.length : a.length;
        int c[] = new int[minlen];
        int k=0;
        for(int i=0;i<b.length;i++){
            int result = binarySearch(a,0,a.length,b[i]);
            if(result > -1){
                c[k++] = a[result];
            }
        }
        int arr[] = new int[k];
        // copy the final array to remove unwanted 0's from the array c
        System.arraycopy(c, 0, arr, 0, k);
        return arr;
    }

    public static void insertionSort(int array[]) {
        for (int i = 1; i < array.length; i++) {
            int j = i;
            int b = array[i];
            while ((j > 0) && (array[j - 1] > b)) {
                array[j] = array[j - 1];
                j--;
            }
            array[j] = b;
        }
    }

    static int binarySearch(int arr[], int low, int high, int num) {
        if (high < low)
            return -1;
        int mid = (low + high) / 2;
        if (num == arr[mid])
            return mid;
        if (num > arr[mid])
            return binarySearch(arr, (mid + 1), high, num);
        else
            return binarySearch(arr, low, (mid - 1), num);
    }

    public static void printArray(int[] array) {
        for (int value : array) {
            System.out.print(" "+value);
        }
        System.out.println("\n");
    }
}

Deepak Singhvi
quelle
0

Wenn die Sammlungen bereits sortiert sind, wie in der Frage gezeigt, ist die beste Lösung (noch nicht erwähnt) ein Algorithmus, der wie eine Zusammenführung sortiert ist und in O (n + m) ausgeführt wird.

Vergleichen Sie die ersten Elemente jeder Sammlung. Wenn sie identisch sind, fügen Sie das Element zur Schnittmenge hinzu und fügen Sie beide Elemente aus ihren Sammlungen hinzu. Wenn die Elemente unterschiedlich sind, fügen Sie das Element hinzu, das im Vergleich zum anderen Element größer ist. Wiederholen, bis eine Sammlung leer ist.

Nick
quelle
0

Unter Verwendung von Java 8-Funktionen ist hier ein Algorithmus, der Duplikate innerhalb einer Liste berücksichtigt, anstatt eine Liste in eine Menge umzuwandeln. Keine Sortierung, also nein n log n.

  1. Konvertieren Sie eine der Listen in eine Karte, wobei der Wert die Anzahl der Vorkommen ist (Kosten: O (n)).
  2. Wenn für jedes Element in der anderen Liste das Element in der Karte vorhanden ist, verringern Sie das Auftreten um eins (Kosten: O (n)).

Daher betragen die Gesamtkosten O (n). Code:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Dup {
  public static void main(String[] args) {
    List<Integer> listA = Arrays.asList(3, 1, 4, 1, 9, 5, 9);
    List<Integer> listB = Arrays.asList(2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3);
    findCommons(listA, listB);
  }

  static void findCommons(List<Integer> listA, List<Integer> listB) {
    Map<Integer, Long> mapA = 
        listA.stream().collect(
            Collectors.groupingBy(Integer::intValue, Collectors.counting()));

    List<Integer> commons = new ArrayList<>();
    listB.stream()
        .filter(e -> mapA.get(e) != null)
        .filter(e -> mapA.get(e) > 0)
        .forEach(e -> {
            mapA.put(e, mapA.get(e) - 1);
            commons.add(e);
        });

    System.out.println(commons);
  }
}

Der obige Code gibt diese Ausgabe aus : [5, 3, 9, 9].

Mohsenmadi
quelle
0

import java.util.Scanner;

public class arraycommon {

public static void main(String[] args) {
    Scanner sc=new Scanner(System.in);
    // display common element in two diffrent array
    int sizea,sizeb,i=0,j=0,k=0;
    int count=0;
    System.out.println("enter the size array A:"+'\n');
    sizea=sc.nextInt();
    System.out.println("enter the size array B"+'\n');
    sizeb=sc.nextInt();
    int a[]=new int[sizea];
    int b[]=new int[sizeb];
    int c[]=new int[sizea];


    System.out.println("enter the element in array A:"+'\n');
    for (i = 0; i < sizea; i++) {

        a[i]=sc.nextInt();
    }
    System.out.println("enter the element in array B:"+'\n');
    for (i = 0; i < sizeb; i++) {

        b[i]=sc.nextInt();
    }
    System.out.println("the element in array A:"+'\n');
    for (i = 0; i < sizea; i++) {

        System.out.print(a[i]+" ");

    }
    System.out.println('\n');
    System.out.println("the element in array B:"+'\n');
    for (i = 0; i < sizeb; i++) 
    {

        System.out.print(b[i]+" ");
    }

    for (i = 0; i <sizea; i++) 
    {
        for (j = 0; j < sizeb; j++) 
        {
           if(a[i]==b[j])
           {
               count++;
               c[k]=a[i];
               k=k+1;
           }
        }
    }
    System.out.println('\n');
    System.out.println("element common in array is");

    if(count==0)
    {
        System.out.println("sorry no common elements");
    }
    else
    {
        for (i = 0; i <count; i++) 
        {

        System.out.print(c[i]+" ");
        }
    }

}

}}

user6885473
quelle
Eine Erklärung des Codes würde diese Antwort hilfreicher machen.
Tot Zam
0
    simply search each element of first array with each element of second array and stored matched result in third array
class Union
{
  public static void main(String[] args) {
  char a[] ={'f','g','d','v','a'};
  char b[] ={'a','b','c','d','e'};
  char temp[] = new char[5];
  int p=0;
  for(int i=0;i<a.length;i++)
  {
    for(int j=0;j<b.length;j++)
    {
      if(a[i]==b[j])     //searches if both array has common element
      {

        temp[p] = a[i];   //if match found store it in a new array
        p++;
      }

    }

  }
  for(int k=0;k<temp.length;k++)
  {
      System.out.println(temp[k]);
  }

  }
}
Akash Salunkhe
quelle
Dies ist eine Brute-Force-Methode, die nicht sehr effizient ist.
Harsh Wardhan