Sword Finger Offer-30-Array Number Over Half

Posted by medaswho on Thu, 16 May 2019 16:29:13 +0200

subject

There is a number in the array that appears more than half the length of the array. Find out that number. For example, enter an array of length 9 {1, 2, 3, 2, 2, 2, 5, 4, 2}. Since the number 2 appears five times in the array, more than half the length of the array, output 2. If not, output 0.

analysis

Preparatory knowledge

If there are more than half of the numbers in the array, then for sorted arrays, the number in the middle of the array must be more than half of the numbers.

Train of thought

The conventional way of thinking is to do it by means of sorting.
Combining the conclusions in the preliminary knowledge, array[middle] may be the result we want. Finally, we'll go through the array and count the number of times equal to that value to see if it's more than half the number of occurrences.

    /**
     * sort
     * @param array
     * @return
     */
    public static int MoreThanHalfNum_Solution(int [] array) {
        if(array == null) {
            return 0;
        }
        Arrays.sort(array);
        int result = array[array.length >> 1];
        if(checkValid(array, result)) {
            return result;
        }
        return 0;
    }

    /**
     * Check whether the value actually appears more than half the time
     * @param array
     * @param value
     * @return
     */
    public static boolean checkValid(int[] array, int value) {
        int count = 0;
        for(int i = 0; i < array.length; i++) {
            if(array[i] == value) {
                count++;
            }
        }
        return count > (array.length >> 1);
    }

Train of thought two

With the help of sorting, the complexity depends on the complexity of the sorting algorithm. Can we continue to optimize?
Yes, the usual way is to change space for time, apply for a map, the value of the array is the key, and the value is the number of statistics keys.
In this way, the time complexity is reduced to O(n), which is mainly spent on traversal.

    /**
     * The idea of hashing is that the value of an array is the key and the number of times is the value.
     * @param array
     * @return
     */
    public static int MoreThanHalfNum_Solution2(int [] array) {
        if(array == null) {
            return 0;
        }
        Map<Integer, Integer> count = new HashMap<>();
        int targetCount = array.length >> 1;
        for(int i = 0; i < array.length; i++) {
            count.put(array[i], (count.get(array[i]) == null ? 0 : count.get(array[i])) + 1);
            if(count.get(array[i]) > targetCount) {
                return array[i];
            }
        }
        return 0;
    }

Train of thought three

Based on the idea of fast platoon, we all know that an important function in fast platoon is partion, which can put all values smaller than sentry on its left.
The values greater than the sentry are placed on its right side, and then the main function of the fast platoon can continue to recurse this operation on the left and right parts until the scale of the sub-problem is 1.
When we look at the partion function, we can see that it can naturally find the maximum value of K. If pivot is positioned exactly at k, then it is the largest value of K in the current array, because the left side is smaller than it, and the right side is larger than it. So the question is how to make sure pivot is exactly where k is.
This is to be processed recursively as fast row. If the pivot is larger than k, it means that the left part of the pivot is located on its left side, so we can continue to process the left part.
If the position of pivot is less than k, it means that the position of the largest K is on the right side of pivot, so we can continue processing some parts.
Until pivot is equal to K. In this way, we can find the value of the largest K, and check whether it really appears more than half of the value after renting.

    /**
     * The idea of quick sorting, partion-based, adjusting arrays
     * Make the value of the k index in the array the value of kth
     * @param array
     * @return
     */
    public static int MoreThanHalfNum_Solution3(int [] array) {
        if(array == null) {
            return 0;
        }
        int targetIndex = array.length >> 1;
        findKthValue(array, 0, array.length - 1, targetIndex);
        if(checkValid(array, array[targetIndex])) {
            return array[targetIndex];
        }
        return 0;
    }

    public static void findKthValue(int[] array, int low, int high, int k) {
        if(low < high) {
            int randomPivot = new Random().nextInt(high - low + 1) + low;
            swap(array, randomPivot, high);
            int index = low;
            for(int i = low; i < high; i++) {
                if(array[i] < array[high]) {
                    swap(array, index, i);
                    index++;
                }
            }
            swap(array, index, high);
            if(index > k) {
                findKthValue(array, low, index - 1, k);
            }else if(index < k){
                findKthValue(array, index + 1, high, k);
            }
        }
    }

    public static void swap(int[] array, int i, int j) {
        if(i != j) {
            int temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
    }

Train of thought four

The bull's way of doing it is pointing to the Office's logo. You can see that if a number appears more than half of the times, it will appear more times than the sum of other arrays. When traversing an array, we can save two values: one to indicate the number of times it currently occurs more than 0, and the other to indicate the number of times it occurs. The practices are as follows:
1. How to update the value to the current value when the current number is 0 and set its occurrence number to 1?
2. If the current value is the same as the saved value, the number of occurrences is increased by 1
3. If the current value is different from the saved value, the number of occurrences is reduced by 1.

Then the last saved value may be the required value. Because if the number of its occurrence really exceeds half, then its occurrence must not be eliminated by other different numbers. It's better to check whether more than half of them actually appear.
There is a more compelling explanation for the above: [Author: cm Asks Future] https://www.nowcoder.com/questionTerminal/e8a1b01a2df14cb2b228b30ee6a92163)

Using the thought of position attack and defense:
The first number serves as the first soldier to defend the position; count=1;
Encounter the same element, count ++;
Encounter different elements, that is, the enemy, the same end, count -;
When count s are zero, the soldiers who take the new i value as the guard position continue to be the main element.
Add another cycle and record the number of soldiers to see if it is larger than the array.

    public static int MoreThanHalfNum_Solution4(int [] array) {
        if(array == null) {
            return 0;
        }
        int result = 0, count = 0;
        for(int i = 0; i < array.length; i++) {
            if(i == 0 || count == 0) {
                result = array[i];
                count++;
            } else if(array[i] == result) {
                count++;
            }else {
                count--;
            }
        }
        if(checkValid(array, result)) {
            return result;
        }
        return 0;
    }

summary

Think more about the combination of ranking and search, but you can take another shortcut.

Topics: less