web-dev-qa-db-de.com

Wie erhalte ich die Kreuzung zwischen zwei Arrays als neues Array?

Ich habe dieses Problem viele Male in verschiedenen Situationen gesehen. 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 bekomme ich die gemeinsamen Elemente zwischen den beiden Arrays als neues Array? In diesem Fall ist der Schnittpunkt von Array A und B char[] c = {'c', 'd'}.

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

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

67
Ranjan Sarma

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

Wenn die Eingangsgröße konstant ist, hat das Problem eine Komplexität von O (nxm) (Länge der beiden Eingänge).

12
Moataz Elmasry
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 zeitlich O(N) und O(N) im Raum. 

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

108
codaddict

Die untere Grenze der Effizienz ist O(n) - Sie müssen mindestens alle Elemente lesen .. _ Dann gibt es mehrere Ansätze:

Dummer einfachster Ansatz

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

Sortieransatz

Sie müssen nur Array eins sortieren und dann mithilfe von Binärsuche nach Elementen aus Array 2 suchen. Zeitkomplexität: Sortieren von O (nlogn), Suchen von O (n * logn) = O (nlogn), Gesamt O (nlogn).

Hash-Ansatz

Erstellen Sie eine Hashtabelle aus Elementen von Array Eins. Suchen Sie nach Elementen aus der zweiten Tabelle in der Hashtabelle. 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 der Hashfunktionseffizienz ist (zwischen 1 und 2).

Einige Hash-Funktionen erstellen garantiert eine Tabelle ohne Kollisionen. Das Gebäude braucht jedoch nicht mehr strikt O(1) Zeit für jedes Element. In den meisten Fällen ist dies O(1), aber wenn die Tabelle voll ist oder eine Kollision auftritt, muss die Tabelle erneut gewaschen werden, wobei O(n) Zeit benötigt wird. Dies passiert nicht so oft, viel seltener als saubere Zusätze. Daher ist die AMORTISIERTE Zeitkomplexität O (1). Es ist uns egal, ob einige der Additionen O(n) Zeit benötigen, solange die Mehrheit der Additionen O(1) Zeit benötigt.

Im Extremfall muss die Tabelle jedoch bei jeder Einfügung erneut gewaschen werden, so dass die strikte zeitliche Komplexität O (n ^ 2) wäre.

33
Jakub Zaverka

Es gibt einige Methoden in einigen Sprachen, von denen ich weiß, dass sie genau das tun, was Sie möchten. Haben Sie in Betracht gezogen, 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
21
Mike
    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;
    }
5
Mik378
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
4

Google Guava

Es gibt bereits viele gute Antworten, aber wenn Sie den One-Liner-Ansatz mit einer Bibliothek für Lazy-Codierung verwenden möchten, würde ich mit Google Guava (für Java) und seiner Sets.intersection -Methode gehen.

(kein Compiler zur Hand, trag 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))
);

Offensichtlich wird davon ausgegangen, dass beide Arrays keine Duplikate hätten. In diesem Fall wäre die Verwendung einer Set-Datenstruktur sinnvoller und würde diese Art der Operation effizienter ermöglichen, insbesondere wenn Sie nicht von Anfang an mit einem Array von Primitiven beginnen .

Möglicherweise passt Ihr Anwendungsfall möglicherweise nicht, aber für den allgemeinen Fall ist dies eine einfache Vorgehensweise.

3
haylem

Wenn Sie auf Duplikate Wert legen, verwenden Sie eine Hash-Map, um die Liste A zu indexieren, wobei der Schlüssel das Element ist und der Wert eine Anzahl der Male ist, wie oft das Element gesehen wurde. 

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

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

Zum Schluss wiederholen Sie die Map und für jedes Element, das den Wert! = 0 hat, wird es als Differenz ausgegeben.

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 in O(n) laufen, da wir nur einmal die Listen und einmal die Map durchlaufen. Die Datenstrukturen, die hier in Java verwendet werden, sollten effizient sein, da HashMap mit einer Kapazität ausgestattet ist, die die größte Größe der Listen verarbeiten kann. 

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

2
Nicholas
  1. Sortieren Sie beide Arrays. 
  2. Dann machen Sie eine Schleife, bis sie gemeinsame Elemente haben. Oder eines der Arrays erreicht sein Ende.

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

2
P.P.

Zuerst sortieren Sie die beiden Arrays mit dem besten Sortieralgorithmus.
Bei linearer Suche können Sie dann die gemeinsamen Elemente abrufen.

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

1
kishore

Zuerst zwei Arrays sortieren, dann iterieren, wenn sie dasselbe Element sind, zu dem zurückgegebenen Array hinzufügen.

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, 
1
Alan Dong

Am besten beginnen Sie gar nicht mit Arrays. Arrays sind optimal für den wahlfreien Zugriff auf Elemente, jedoch nicht optimal für die Suche. Wenn Sie von intersection sprechen, müssen Sie die Arrays als Mengen betrachten. Verwenden Sie daher eine geeignetere Datenstruktur (in Java eine Set). Dann ist die Aufgabe viel effizienter.

1
Raedwald

in Ruby kann man nur sagen

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

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

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

1
Yola

importieren von Java.util.Scanner;

öffentliche Klasse 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]+" ");
        }
    }

}

}

0
user6885473

Angenommen, Sie haben 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]]++;
}

Jetzt iterieren Sie über 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 erfordert O(n) Zeitkomplexität und einen konstanten Platz für Ihre Prüfungen, wobei Ihr neues Array/Liste nicht berücksichtigt wird, das für die gemeinsamen Elemente verwendet wird.

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

0

Sortiere eines der Arrays (m Log (m)) Now Wähle jedes Element aus einem anderen Array und Suche eine binäre Suche im ersten Array (das sortierte) -> n Log (m)

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

0
navgupta

Bei Verwendung von Java 8-Funktionen wird hier ein Algorithmus verwendet, der Duplikate innerhalb einer Liste berücksichtigt, anstatt aus einer Liste einen Satz zu machen. Keine Sortierung, also kein n log n.

  1. Konvertieren Sie eine der Listen in eine Karte. Der Wert ist die Anzahl der Vorkommen (Kosten: O (n)).
  2. Wenn für das Element in der anderen Liste ein Element in der Karte vorhanden ist, verringern Sie das Vorkommen 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);
  }
}

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

0
mohsenmadi

Ich hoffe das folgende wäre nützlich. Dies sind zwei unterschiedliche Ansätze:

  • Einfache Überschneidung, bei der Sie alle Elemente eines Arrays mit einem anderen Array vergleichen.

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

//

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");
    }
}
</ code>
0
Deepak Singhvi

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

0
Sanj
    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]);
  }

  }
}
0
Akash Salunkhe

Wenn die Sammlungen bereits sortiert sind (siehe Frage), ist die beste Lösung (noch nicht erwähnt) ein Merge-Sortier-Algorithmus, der 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 schließen Sie beide Elemente aus ihren Sammlungen. Wenn die Elemente unterschiedlich sind, platzieren Sie das Element, das im Vergleich zum anderen Element größer ist. Wiederholen Sie diesen Vorgang, bis eine Sammlung leer ist.

0
Nick