2016-06-09 3 views
1

정렬 된 배열에 특정 숫자가 나타나는 횟수를 찾는 효율적인 방법을 찾고 있습니다.정렬 된 배열에 숫자가 나타나는 횟수를 검색하는 가장 효율적인 방법

내 현재 코드는 : 그것은 요소의 몇 10 초를인지

public class Numbers { 

    public static void main(String[] args) { 
     int[] x = new int[]{1,2,3,4,4,7,7,7,7,7,8}; 
     int count = 0; 
     for (int i = 0; i < x.length; ++i) 
      if (x[i] == 7) ++count; 
     System.out.println(count); 
    } 
} 
+2

배열 x은 정렬되지 않습니다. 이진 검색을 사용하여 숫자의 수를 찾을 수 있습니다. –

+2

물론입니다. n-1에 대한 이진 검색, n + 1에 대한 이진 검색, 사이에있는 요소의 수를 찾습니다. –

+0

바이너리 접근법이 O (logn) – Keiwan

답변

1

대답은 정말 선형 스캔을 할 아마 더 효율적, 배열이 시간에 따라 달라집니다. 그것은 더 큰 배열의 경우 다음과 같이 내가 Array.binarySearch()를 사용하는 것이 좋습니다 것 :이 항목은 배열에있는 경우

public static void main(String[] args) { 
    int[] x = new int[]{1,2,3,4,4,7,7,7,7,7,8}; 
    int index = Arrays.binarySearch(x, 7); 
    System.out.println(index); 
    int count = 0; 
    if (index >= 0) { 
     // search down 
     int i = index - 1; 
     for (; i >= 0 && x[i] == 7; --i) { 
     } 
     // search up 
     for (++index; index < x.length && x[index] == 7; ++index) { 
     } 
     count = index - (i + 1); 
    } 
    System.out.println(count); 
} 

첫째 이진 검색이 당신을 말할 것이다,이 경우, 당신은 정말 어디에 모른다 검색 범위에서 요소를 찾았으나 정확한 계산을 위해 양방향으로 선형 스캔을해야하지만 비교 횟수는 많아야이 특정 키의 수입니다. (이진 검색)

+1

바이너리 검색 사용을 제안했을 때 다른 사람이 의미하는 바는 아닙니다. – Chill

+0

@Chill - 네, 알아요.하지만 다른 제안은 * 계산 * 문제로 작동하지 않습니다. – Nim

+0

계산을 사용하지 않는 솔루션을 추가했습니다. 배열이 정렬된다는 사실을 이용합니다. – Chill

3

설명에서 언급 한 것처럼 배열이 정렬되므로 2 진수 검색을 수행하여 숫자가 나타나는 배열에서 가장 낮은 인덱스를 찾고 번호가 나타나는 가장 높은 인덱스를 찾을 수 있습니다. 이진 검색을 사용하여 색인을 찾고 O (log n) 알고리즘을 얻습니다.

일부 다른 배열 값으로이 코드를 사용해보십시오.

public static void main(final String[] args) { 
    final int numberToCount = 7; 

    final int[] x = new int[]{1,2,3,4,4,6,6,6,6,7,7,7,7,7,8,8,8,8,8,8}; 

    final int indexOfKnownOccurence = Arrays.binarySearch(x, numberToCount); 
    if (indexOfKnownOccurence < 0) { 
     System.out.println("No instances of the number found"); 
     return; 
    } 

    final int lowerBound = findIndexOfFirstOccurence(x, numberToCount, 0, indexOfKnownOccurence); 

    final int upperBound = findIndexOfLastOccurence(x, numberToCount, indexOfKnownOccurence, x.length - 1); 

    System.out.println("Lower bound: " + lowerBound); 
    System.out.println("Upper bound: " + upperBound); 
    System.out.println("Number of occurrences: " + (upperBound - lowerBound + 1)); 
} 

//Binary search for start index 
public static int findIndexOfFirstOccurence(final int[] x, final int numberToFind, final int startIndex, final int endIndex) { 
    if (startIndex == endIndex) { 
     return startIndex; 
    } else if (x[startIndex] == numberToFind) { 
     return startIndex; 
    } else if (startIndex + 1 == endIndex) { 
     return endIndex; 
    } 

    final int midIndex = startIndex + (int)Math.floor((endIndex - startIndex)/2); 

    if (x[midIndex] == numberToFind) { 
     return findIndexOfFirstOccurence(x, numberToFind, startIndex, midIndex); 
    } else { 
     return findIndexOfFirstOccurence(x, numberToFind, midIndex, endIndex); 
    } 
} 

//Binary search for end index 
public static int findIndexOfLastOccurence(final int[] x, final int numberToFind, final int startIndex, final int endIndex) { 
    if (startIndex == endIndex) { 
     return endIndex; 
    } else if (x[endIndex] == numberToFind) { 
     return endIndex; 
    } else if (startIndex + 1 == endIndex) { 
     return startIndex; 
    } 

    final int midIndex = startIndex + (int)Math.floor((endIndex - startIndex)/2); 

    if (x[midIndex] == numberToFind) { 
     return findIndexOfLastOccurence(x, numberToFind, midIndex, endIndex); 
    } else { 
     return findIndexOfLastOccurence(x, numberToFind, startIndex, midIndex); 
    } 
} 
+0

이것은 실제로 그들이 의미하는 것이 아닙니다! ;) 그러나이 분류 된 이진 검색이 선형 스캔을 통한 노력만큼 가치가 있는지 여부를 비교하여 (잠재적으로) 비교 횟수를 줄이면 내 제안이 향상됩니다. 프로파일 링을 통해 실제로 결정해야합니다. – Nim

+0

나는 의견에서 다른 사람들이 말하는 것을 오해 했음에 틀림 없다. 그러나 이것이 최악의 이론적 관점에서 볼 때 최적이라고 생각합니다. 큰 목록의 경우 더 좋을 수 있지만 작은 목록을 말하기는 어렵습니다. – Chill

관련 문제