leetcode 169. 多数元素(众数)& 剑指 Offer 39. 数组中出现次数超过一半的数字 & 面试题 17.10. 主要元素(投票算法)

【题目】169. 多数元素 & 剑指 Offer 39. 数组中出现次数超过一半的数字

169. 多数元素)& 面试题39. 数组中出现次数超过一半的数字一定存在众数, 面试题 17.10. 主要元素不一定存在众数

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

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

示例 2:

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

【解题思路1】排序

出现次数最多的元素大于n/2次的就是众数,暴力法会超时,所以可以先排序,然后下标是n/2的元素一定是众数,n为奇数或者偶数都可以。
leetcode 169. 多数元素(众数)& 剑指 Offer 39. 数组中出现次数超过一半的数字 & 面试题 17.10. 主要元素(投票算法)_第1张图片

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;
    }
}

【题目】 面试题 17.10. 主要元素

数组中占比超过一半的元素称之为主要元素。给定一个整数数组,找到它的主要元素。若没有,返回-1。

示例 1:

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

示例 2:

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

示例 3:

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

说明:
你有办法在时间复杂度为 O(N),空间复杂度为 O(1) 内完成吗?

【解题思路4】位运算

  • 构造ans使得它是主要元素。
  • 由于主要元素是数组中多一半的数,那么这个主要元素的每位二进制也是数组每个元素二进制数中多一半的数
  • 统计每位数字的第i位二进制,假如第i位为1比较多,那么将ans的第i位置为1,否则为0
class Solution {
    public int majorityElement(int[] nums) {
        int ans = 0;
        int n = nums.length;
        //统计每位数字的第i位二进制
        for(int i = 0; i < 32; i++){
            int cnt = 0;
            for(int j = 0; j < n; j++){
                //如果第i位为1
                if((nums[j] >> i & 1) == 1) cnt++;
            }
            //如果所有数字的二进制数中,第i位1比0多
            if(cnt > n / 2) ans ^= (1 << i);
        }
        int C = 0;
        for(int i = 0; i < n; i++) {
            if(nums[i] == ans) C++;
        }
        if(C <= n / 2) ans = -1;
        return ans;
    }
}

你可能感兴趣的:(Leetcode,/,Online,Judge,#,重复数,#,分治,leetcode,分治算法,摩尔投票算法)