2009-12-05 21 views
10

Przyjmijmy, mam tablicę podwaja, który wygląda tak:Określić najbardziej powszechnym zjawiskiem w tablicy

Array[10] = {10, 10, 10, 3, 10, 10, 6, 10, 10, 9, 10} 

Potrzebuję funkcji, które można określić, co głosowanie MAJORTY jest w tablicy, w tym przypadku "10", ponieważ jest to liczba, która pojawia się najczęściej ... I oczywiście jest sytuacja, w której nie ma większości (gdzie są równe), w tym przypadku muszę rzucić wyjątek ...

Jakieś wskazówki? Oprócz wykonywania naprawdę nieprzyjemnych pętli w tablicy (dla każdego indeksu określ, ile istnieje z tą samą wartością, przechowuj liczbę w tablicy, a następnie skanuj tablicę liczników dla największej liczby, a wartość na tej pozycji jest zwycięzcą , itd ...)

+0

tag go jako algorytm :) – DarthVader

+0

można zrobić sortowanie przez zliczanie. a potem znajdziesz większość. Jeśli rozmiar macierzy powiększa się, sortowanie zliczania staje się wydajne. – DarthVader

+0

To brzmi jak zadanie domowe, byłbym zaskoczony, gdybyś potrzebował tego w prawdziwym programie. ;) –

Odpowiedz

17

Korzystanie z Map<Integer, Integer> powinny być proste, jak:

int mostFrequent(int... ary) { 
    Map<Integer, Integer> m = new HashMap<Integer, Integer>(); 

    for (int a : ary) { 
     Integer freq = m.get(a); 
     m.put(a, (freq == null) ? 1 : freq + 1); 
    } 

    int max = -1; 
    int mostFrequent = -1; 

    for (Map.Entry<Integer, Integer> e : m.entrySet()) { 
     if (e.getValue() > max) { 
      mostFrequent = e.getKey(); 
      max = e.getValue(); 
     } 
    } 

    return mostFrequent; 
} 
+0

Istnieje również torba na kolekcje Apache Commons (http://commons.apache.org/collections/apidocs/org/apache/commons/collections/bag/HashBag.html) i Multiset z kolekcji Google (http: // google- collections.googlecode.com/svn/trunk/javadoc/index.html?http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/package-summary.html) Mogą one być łatwiejszym lub może być przesadą, w zależności od tego, co OP potrzebuje, ale po prostu chciał o nich wspomnieć. – hexium

+0

Ponieważ jest to poprawna odpowiedź, zasługuje ona na więcej awansów! – RichardOD

5

Twój pierwszy problem polega na tym, że masz "tablicę podwójnych", ponieważ równość jest problematyczna w przypadku danych zmiennoprzecinkowych (identyczne wartości liczbowe mogą być reprezentowane między innymi przez różne wzory bitowe). Jeśli twoje duble są w rzeczywistości (jak w przykładzie) liczbami całkowitymi, użyj zamiast tego int. Innymi słowy, zastanówcie się długo, jak określić, jakie wartości są równe w celu reprezentowania tego samego głosu.

Jeśli chodzi o ustalanie większości głosów, należy użyć Map z "id głosowania" jako kluczem i liczbą głosów jako wartością - następnie na końcu należy przejść przez mapę, aby znaleźć maksymalną wartość.

+2

Jeśli wszystkie wartości są liczbami całkowitymi, to podwójne będzie działać doskonale. Nie powinieneś także przejmować się wzorcami bitów, == zwróci wartość true, a wartości będą równe liczbowo (z wyłączeniem tylko NaN). Kwestia, jeśli występuje, z podwójnym jest to, czy wartości, które są bardzo blisko, należy uznać za równe. Odpowiedź zależy od źródła wartości (np. Czy wynikają one z pewnego fizycznego procesu pomiarowego). –

+1

Wszystko zależy od tego, w jaki sposób docierasz do wartości, których używasz. Na przykład, użycie float do zaostrzenia problemów dokładności: 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f! = 1.0f - 0.1f - 0.1f Takie przykłady są łatwe do znalezienia przez. – PSpeed

+0

@ Mark Thornton, PSpeed ​​ma rację. Identyczność jest zachowywana tylko wtedy, gdy zmiennoprzecinkowe były bezpośrednio tworzone/konwertowane, a nie wynikiem innych wyrażeń zmiennoprzecinkowych. Jako taki jest to zabawny przykład, a nie rzeczywisty świat, potrzebowalibyśmy trochę epsilonu do porównania równości. – smci

4

Posortuj najpierw tablicę z/szybko sortuj, a następnie zeskanuj i policz do większości - O (n ln n). Jeśli zakres elementów jest znany z wyprzedzeniem, powiedzmy między {1, k}, można zastosować sortowanie liczące, które będzie działało w O (n + k).

Jako niewielką poprawę, gdy skanujesz posortowaną tablicę, jeśli znajdziesz wartość, która ma więcej niż n/2 wystąpień, skończysz.

+1

dla 10 elementów, sortowanie szybkie przebiegałoby szybciej niż sortowanie zliczające :) – DarthVader

+1

chyba że zostały już posortowane .... :) – Paul

+0

Jak możemy napisać kod dla tego rozwiązania, które używa "sortowania"? Próbowałem pisać, ale mój kod nigdy się nie kończy. Oto mój kod: http://ideone.com/eKOWOV – Hengameh

0

Można to zrobić: Konwertuj tablicę na listę i ją posortuj. Wybierz pierwszy indeks i wywołaj lastIndexOf (obj) na wartości. Zrób to dla każdej nowej wartości, którą napotkasz, obliczyć zakres wartości i zapisać wyniki największego zakresu w zmiennej.

4

Z wieloma sobowtórami może to nie być łatwe, ponieważ porównania równości w deblu są dość problematyczne. Jeśli można uciec z użyciem liczb całkowitych, można zrobić coś jak poniżej:

HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(); 
    for(int element: Array) 
    { 
     Integer frequency = map.get(element); 
     map.put(element, (frequency != null) ? frequency + 1 : 1);  
    } 
    int mostFrequentItem = 0; 
    int[] maxFrequencies = new int[2]; 
    maxFrequencies[0]  = Integer.MIN_VALUE; 

    for(Entry<Integer, Integer> entry: map.entrySet()) 
    { 
     if(entry.getValue()>= maxFrequencies[0]) 
     { 
      mostFrequentItem = entry.getKey(); 
      maxFrequencies[1] = maxFrequencies[0]; 
      maxFrequencies[0] = entry.getValue(); 
     } 
    } 
    if(maxFrequencies[1] == maxFrequencies[0]) 
     throw new Exception();//insert whatever exception seems appropriate 
      return mostFrequentItem 

to będzie musiało O (n) wydajności, więc powinno być całkiem optymalne asymptotycznej zachowanie wydajności. Jeśli twoje duble nie są wynikiem obliczeń, ale pochodzą z innego źródła, to znaczy, jeśli możesz być pewny, że wartości, które są w zasadzie takie same, będą reprezentowane jednakowo, możesz uciec z użyciem tej samej metody dla deblu, jednak nadal zalecamy uważać, że tak jest naprawdę.

Edycja: niektóre ulepszenia wydajności, jak je w komentarzu, a także wspieranie sprawdzania niejednoznacznym przypadku

+0

+1 za podanie O (n). To nie może być szybciej. Niewielką poprawę można uzyskać, wykonując polecenie get zamiast z danych zawartych w dfa. Ale nie wpływa to na złożoność. – PSpeed

0

Co naprawdę chcesz zrobić, to zliczyć wystąpienia niektórych elementów w danym zestawie. W rzeczywistości było to wcześniej zadawane mniej niż dzień temu, możesz zajrzeć do tego very relevant question.

2

Jak @Grizzly wskazuje debel są problematyczne z punktu widzenia obliczeniowego.Sugerowałbym również, że nie mają one sensu z punktu widzenia twojej domeny problemów; debel nie ma sensu z większością głosów!

Pozwala więc założyć, że 10 i 6 i tak dalej są liczbami całkowitymi dla rzeczy, za które ludzie głosują. Załóżmy również, że wiesz, że użytkownicy mogą głosować dowolną wartość z 0 do 10.

int[] votes = ... 
int[] voteCounts = new int[11]; // 11 could be calculated ... 
for (int vote : votes) { 
    voteCounts[vote]++; 
} 
int majority = (votes.length + 1)/2; 
for (int i = 0; i < voteCounts.length; i++) { 
    if (voteCounts[i] >= majority) { 
     return i; // the winner! 
    } 
} 
throw new NoClearMajorityException(...); 

Algorytm ten jest O(N) w czasie i przestrzeni w O(M), gdzie M to największa identyfikator. Połów jest taki, że działa tylko (tak jak zapisano), jeśli identyfikatory są liczbami całkowitymi.

+0

Dlaczego nie sprawdziłeś maksymalnej wartości w tablicy 'voteCounts' i zwróciłeś jej indeks? Ponieważ myślę, że to "int majority =" (votes.length + 1)/2; "może nie być spełnione, ale nadal mamy element większościowy. Na przykład w tej tablicy: 'int [] array1 = {2, 3, 3, 5, 3, 4, 1, 7};', 3 jest większością i nie jest powtarzane 5 razy. (Twoje ograniczenia są również brane pod uwagę, zakres głosowania od 0 do 8) – Hengameh

+1

Dlaczego ja nie? Ponieważ nie o to pyta problem opisany w pytaniu! Wymogiem jest znalezienie ** większości ** wartości i zgłoszenie wyjątku, jeśli nie ma większości. –

+0

Masz na myśli, że 3 nie jest numerem "najczęściej występującym" w tej tablicy? '{2, 3, 3, 5, 3, 4, 1, 7}' Być może, to nieporozumienie wznosi się z różnicy między ''Elementem Większości'' i' 'najczęściej występującym elementem'' w tablicy.(Tytuł mówi: "najczęściej występujący element" i opis mówi: "element większościowy"). W każdym razie, dziękuję za odpowiedź :) – Hengameh

2

Właśnie stworzył taki piękny i małe rozwiązanie z nowym Java 8:

import java.util.Arrays; 
import java.util.Collection; 
import java.util.HashMap; 
import java.util.Map; 

public class MostCommonObject { 
    public static void main(String[] args) { 
     System.out.println(mostCommonObject(new Integer[] { -4, 1, -2, 3, 1, -2, 3, 1 })); 
    } 

    public static <T> T mostCommonObject(T[] array) { 
     return mostCommonObject(Arrays.asList(array)); 
    } 

    public static <T> T mostCommonObject(Collection<T> collection) { 
     Map<T, Integer> map = new HashMap<>(); 
     collection.forEach(t -> map.compute(t, (k, i) -> i == null ? 1 : i + 1)); 
     return map.entrySet().stream().max((e1, e2) -> Integer.compare(e1.getValue(), e2.getValue())).get().getKey(); 
    } 
} 
1

próbować ten jeden,

Integer[] array=new Integer[]{10, 10, 10, 3, 10, 10, 6, 10, 10, 9, 10}; 

    List<Integer> demoList=new ArrayList<Integer>(Arrays.asList(array)); 

    Set<Integer> set=new HashSet<Integer>(demoList); 

    Map<Integer,Integer> myMap=new HashMap<Integer, Integer>(); 

    for (Integer integer : set) 
    { 
     int count=Collections.frequency(demoList, integer); 
     myMap.put(count, integer);    
    } 

    int maxOccurance=myMap.get(Collections.max(myMap.keySet())); 
Powiązane problemy