【剑指Offer】39.数组中出现次数超过一半的数字

题目

给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。

数据范围:0≤n≤50000,数组中元素的值0≤val≤10000

要求:空间复杂度O(1),时间复杂度O(n)

输入描述:

保证数组输入非空,且保证有解

示例1

输入:[1,2,3,2,2,2,5,4,2]

返回值:2

示例2

输入:[3,3,3,3,2,2,2]

返回值:3

示例3

输入:[1]

返回值:1

解答

源代码

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param numbers int整型一维数组 
     * @return int整型
     */
    public int MoreThanHalfNum_Solution (int[] numbers) {
        // write code here
        int cand = -1, cnt = 0;
        for (int num : numbers) {
            if (cnt == 0) {
                cand = num;
                cnt++;
            } else {
                if (cand == num) {
                    cnt++;
                } else {
                    cnt--;
                }
            }
        }

        cnt = 0;
        for (int num : numbers) {
            if (num == cand) {
                cnt++;
            }
        }

        if (cnt > numbers.length / 2) {
            return cand;
        }

        return 0;
    }
}

总结

比较直接可以想到的方法就是用遍历数组用哈希表来存储每个数的出现次数,之后再遍历哈希表,查询是否存在一个数字出现的次数超过数组长度的一半。

如果不想使用额外的空间,也可以对数组进行排序,如果存在这样的数字,那么它一定存在于数组中间。

从官方题解里学习了一个很有趣的方法,如果存在一个数字出现的次数超过数组长度的一半,那么将这个数组中不相等的数字两两相消,最后剩下的一定是这个数字。

我们用这个思路来解决问题:

1. 初始化:候选人cand = -1, 候选人的投票次数cnt = 0

2. 遍历数组,如果cnt=0, 表示没有候选人,则选取当前数为候选人,++cnt

3. 否则,如果cnt > 0, 表示有候选人,如果当前数=cond,则++cnt,否则--cnt

4. 直到数组遍历完毕,最后检查cand是否为众数

你可能感兴趣的:(剑指Offer,算法,数据结构,java,数组)