AdSense

Monday, November 21, 2016

Amazing number

Define amazing number as: its value is less than or equal to its index. Given a circular array, find the starting position, such that the total number of amazing numbers in the array is maximized.Example 1: 0, 1, 2, 3 Ouptut: 0. When starting point at position 0,
all the elements in the array are equal to its index.
So all the numbers are amazing number.Example 2: 1, 0 , 0Output: 1. When starting point at position 1,
the array becomes 0, 0, 1. All the elements are amazing number.If there are multiple positions, return the smallest one.should get a solution with time complexity less than O(N^2)

Brutal force is trivial: For each index as starting point, count number of amazing number in the array, then update index if we see a max.

There is a clever way of doing it in the original post, which utilizes interval. For any number, if it's larger than the length of the array, there is no way we can make it an amazing number. Otherwise, starting from the next index of the current one can always make the number an amazing number. The largest index would be length_of_array + current_index - array[current_index]. This is because current_index - array[current_index] is the index we need to make the number an amazing number. If the number is larger than current index, this index will become negative, so we need to add length of array to keep the index in the array. For current_index > array[current_index], this operation will lead to index > length of array, so we mod the index by length.

After we get all intervals, we need to find the index that all intervals intersects most, which is the index that contains the most amazing numbers. To do that, we can use algorithm in Range Addition.


public int getAmazingNumber(int[] array) {
        List<Interval> startIndexInterval = new ArrayList<>();
        int len = array.length;
        for (int i = 0; i < len; i++) {
            if (array[i] >= len) {
                continue;
            }
            // for i = len - 1, next interval
            int start = (i + 1) % len;
            // for array[i] < i, mod to make sure index is in the array
            //which may lead start > end
            int end = (i - array[i] + len) % len;
            startIndexInterval.add(new Interval(start, end));
        }

        int[] indexCount = new int[len];
        for (Interval interval : startIndexInterval) {
            indexCount[interval.start]++;
            //for start > end, we need to split interval to two
            //[start, len - 1], [0, end]
            if (interval.start > interval.end) {
                indexCount[0]++;
            }
            if (interval.end + 1 < len) {
                indexCount[interval.end + 1]--;
            }

        }
        int max = indexCount[0];
        int rstIndex = 0;
        for (int i = 1; i < len; i++) {
            indexCount[i] += indexCount[i - 1];
            if (indexCount[i] > max) {
                rstIndex = i;
                max = indexCount[i];
            }
        }
        return rstIndex;
    }


1 comment:

  1. hello

    I can not understand the following statement:
    "Otherwise, starting from the next index of the current one can always make the number an amazing number. "

    if we have 10 element array and at array[2] = 6 then by setting 3 as start position to the interval will not make the 6 amazing number ... Am i missing something?

    10x

    ReplyDelete