简体   繁体   中英

Most efficient way to search how many times a number appears in a sorted array

I am looking for an efficient way to find how many times a particular number appears in a sorted array.

My current code:

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);
    }
}

Since the array is sorted, as mentioned in the comments, you can perform 2 binary searches to find the lowest index in the array where the number appears and the highest index where the number appears. Add in a binary search to find some index, and you get an O(log n) algorithm.

Try this code out with some different array values.

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);
    }
}

The answer really depends on how long your array is, if it's only few 10s of elements, it's probably more efficient to do a linear scan. If it's a larger array, I'd recommend using Array.binarySearch() as in the following:

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);
}

Firstly binary search will tell you if this item is present in the array, if it is, you don't really know where in the range the search found the element, but you have to do a linear scan in both directions to determine the exact count, however the number of comparisons you have to do is at most the count of this particular key... (excluding the binary search)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM