剑指offer数组中出现次数超过一半的数字

题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
 
三种解法:
 
1. 用map将number和出现次数存起来。
时间复杂度O(n), 空间复杂度O(n)
import java.util.HashMap;

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        HashMap<Integer, Integer> map = new HashMap<>();
        if (array.length == 1) return array[0];
        for (int i = 0; i < array.length; i++) {
            if (map.containsKey(array[i])) {
                int count = map.get(array[i]);
                if (count >= array.length / 2)
                    return array[i];
                map.put(array[i], count + 1);
            }
            else {
                map.put(array[i], 1);
            }
        }
        return 0;
    }
}
2. 出现超过一半的数字一定是中位数,但中位数不一定是超过一半的数字(可能不存在这样的数字),先利用position算法得到中位数,再验证是否为出现超过一半的数字。
时间复杂度O(n),空间复杂度O(1)
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        if (array.length == 0) return 0;
        if (array.length == 1) return array[0];
        int left = 0;
        int right = array.length - 1;
        
        while (left < right) {
            int index = position(array, left, right);
            if (index == array.length / 2) {
                if (checkMoreThanHalf(array, array[index]))
                    return array[index];
                else 
                    return 0;
            }
                
            else if (index < array.length / 2)
                left = index + 1;
            else 
                right = index - 1;
        }
        
        return 0;
    }
    
    private int position(int[] array, int start, int end) {
        int index = start + (int)Math.random() * (end - start);
        swap(array, index, end);
        
        int small = start - 1;
        for (int i = start; i < end; i++) {
            if (array[i] <= array[end] && ++small != i) {
                swap(array, small, i);
            } 
        }
        
        swap(array, ++small, end);
        return small;
    }
    
    private void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    } 
    
  //验证数组是否合理
private boolean checkMoreThanHalf (int[] array, int result) { int times = 0; for (int i = 0; i < array.length; i++) { if (array[i] == result) times++; } if (times * 2 <= array.length) return false; else return true; } }
 
3. 出现超过一半的数字出现的次数一定比其他数字出现的次数之和要大,因此设置两个变量,一个是数组中的数字,另一个是出现次数。遍历数组,当出现相同的数字是,出现次数加1,否则减1,当次数变为0时,记录新的数字。最后一个次数>=1的数字可能为所求的数字。但也需要验证数组是否合理。
时间复杂度O(n),空间复杂度O(1)
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        int len = array.length;
        if (len == 0) return 0;
        if (len == 1) return array[0];
        
        int result = array[0];
        int times = 1;
        
        for (int i = 1; i < len; i++) {
            if (times == 0) {
                result = array[i];
                times = 1;
            }
            else if (array[i] == result) {
                times++;
            }
            else {
                times--;
            }
        }
        
        if (times >= 1 && checkMoreThanHalf(array, result)) 
            return result;
        else 
            return 0;
    }
    
    
    private boolean checkMoreThanHalf (int[] array, int result) {
        int times = 0;
        for (int i = 0; i < array.length; i++) {
            if (array[i] == result)
                times++;
        }
        
        if (times * 2 <= array.length) 
            return false;
        else 
            return true;
    }
}
 
原文地址:https://www.cnblogs.com/weiququ/p/12387259.html