leetcode 169. 多数元素(众数)

【题目】

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:

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

示例 2:

输入: [2,2,1,1,1,2,2]
输出: 2

官方题解

【解题思路1】排序

出现次数最多的元素大于n/2次的就是众数,暴力法会超时,所以可以先排序,然后下标是n/2的元素一定是众数,n为奇数或者偶数都可以。
在这里插入图片描述

class Solution {
    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length/2];
    }
}

【解题思路2】分治-递归

如果元素a是整个数组的众数,那么将数组一分为二,a也必定至少是其中一部分的众数,所以可以将数组分成左右两部分,分别求出左半部分的众数 a1 以及右半部分的众数 a2,随后在 a1 和 a2 中选出正确的众数。
分治递归求解,直到所有的子问题都是长度为 1 的数组。长度为 1 的子数组中唯一的数显然是众数,直接返回即可。如果回溯后某区间的长度大于 1,我们必须将左右子区间的值合并。如果它们的众数相同,那么显然这一段区间的众数是它们相同的值。否则,我们需要比较两个众数在整个区间内出现的次数来决定该区间的众数。

class Solution {
    private int countInRange(int[] nums, int num, int lo, int hi) {
        int count = 0;
        for (int i = lo; i <= hi; i++) {
            if (nums[i] == num) {
                count++;
            }
        }
        return count;
    }

    private int majorityElementRec(int[] nums, int lo, int hi) {
        // base case; the only element in an array of size 1 is the majority
        // element.
        if (lo == hi) {
            return nums[lo];
        }

        // recurse on left and right halves of this slice.
        int mid = (hi-lo)/2 + lo;
        int left = majorityElementRec(nums, lo, mid);
        int right = majorityElementRec(nums, mid+1, hi);

        // if the two halves agree on the majority element, return it.
        if (left == right) {
            return left;
        }

        // otherwise, count each element and return the "winner".
        int leftCount = countInRange(nums, left, lo, hi);
        int rightCount = countInRange(nums, right, lo, hi);

        return leftCount > rightCount ? left : right;
    }

    public int majorityElement(int[] nums) {
        return majorityElementRec(nums, 0, nums.length-1);
    }
}

【解题思路3】Boyer-Moore 投票算法

这个思路比较有趣。
如果我们把众数记为 +1+1,把其他数记为 -1−1,将它们全部加起来,显然和大于 0,从结果本身我们可以看出众数比其他数多。

  1. 维护一个候选众数 candidate 和它出现的次数 count。初始时 candidate 可以为任意值,count 为 0;
  2. 遍历数组 nums 中的所有元素,对于每个元素 x,在判断 x 之前,如果 count 的值为 0,我们先将 x 的值赋予candidate,随后我们判断 x:
    (1)如果 x 与 candidate 相等,那么计数器 count 的值增加 1;
    (2)如果 x 与 candidate 不等,那么计数器 count 的值减少 1。
  3. 在遍历完成后,candidate 即为整个数组的众数。
[7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]

每一步遍历时 candidate 和 count 的值:

nums:      [7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]
candidate:  7  7  7  7  7  7   5  5   5  5  5  5   7  7  7  7
count:      1  2  1  2  1  0   1  0   1  2  1  0   1  2  3  4
class Solution {
    public int majorityElement(int[] nums) {
        int count = 1;
        int candidate = nums[0];
        for (int i = 1; i < nums.length; i++) {
            if (candidate == nums[i]){
                count++;
            }else {
                count--;
                if (count == 0) {  //若count为0,更换候选人
                    candidate = nums[i];
                    count++;
                }
            }
        }
        return candidate;
    }
}
发布了76 篇原创文章 · 获赞 116 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/XunCiy/article/details/104851232