在一个数组中寻找多数元素

问题描述

多数元素是指出现次数大于数组总长度一半的元素,如数组[1,3,3,3,5,7,3],数组长度为7,元素3出现了4次,大于7/2=3,所以元素3为多数元素。

遍历计数法

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

class Solution {

  public int majorityElement(int[] nums) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int num : nums) {
      map.put(num, map.getOrDefault(num, 0) + 1);
    }
    for (Entry<Integer, Integer> entry : map.entrySet()) {
      if (entry.getValue() > (nums.length / 2)) {
        return entry.getKey();
      }
    }
    return -1;
  }

  public static void main(String[] args) {
    System.out.println(new Solution().majorityElement(new int[]{2, 2, 1, 1, 1, 2, 2}));
  }
}

使用一个HashMap存储每一个元素和它出现的次数。

排序取中项法(前提存在多数元素)

import java.util.Arrays;

class Solution {

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

  public static void main(String[] args) {
    System.out.println(new Solution().majorityElement(new int[]{2, 2, 1, 1, 1, 2, 2}));
  }
}

在一个排好序的数组中,其中间的元素必定是多数元素(如果存在的话)。

使用位运算(前提存在多数元素)

class Solution {

  public int majorityElement(int[] nums) {
    int res = 0;
    int n = nums.length;
    for (int i = 0; i < 32; i++) {
      int ones = 0, zeros = 0;
      for (int num : nums) {
        if (ones > n / 2 || zeros > n / 2) {
          break;
        }
        //num在第i位的值,如3在第0位的值为1,num&(1<<i)的结果要么为0,要么为(1<<i)
        int bit = num & (1 << i);
        if (bit == 0) {
          zeros++;
        } else {
          ones++;
        }
      }
      if (ones > zeros) {
        //将res的第i位置为1,如将3的第2位置为1,就变成了7
        res |= (1 << i);
      }
    }
    return res;
  }

  public static void main(String[] args) {
    System.out.println(new Solution().majorityElement(new int[]{2, 2, 1, 1, 1, 2, 2}));
  }
}

以数组[1,3,3,3,5,7,3]为例,元素3为多数元素,3的二进制表示为

00000000 00000000 00000000 00000011

那么在0位和1位这两个位置的1一定比0多,因为元素3已经占一半以上了。

摩尔投票法(前提存在多数元素)

class Solution {

  public int majorityElement(int[] nums) {
    int count = 0;
    int res = 0;
    for (int num : nums) {
      if (count == 0) {
        count = 1;
        res = num;
      } else {
        if (res == num) {
          count++;
        } else {
          count--;
        }
      }
    }
    return res;
  }

  public static void main(String[] args) {
    System.out.println(new Solution().majorityElement(new int[]{2, 2, 1, 1, 1, 2, 2}));
  }
}

核心原理就是对拼消耗,假设有A,B两个国家,A人口占总人口的一半以上,那么只要A国一个人能够消耗掉B国一个人,最后剩下的一定是A国人,就算B国人内斗也不影响最终结果。
带入到代码中,以数组[1,3,3,3,5,7,3]为例,元素1为B国人,元素3为A国人,最终对拼消耗之后还剩一个3。
以数组[1,1,2,2,3,3,3,3,3]为例,1,2元素都属于B国人,刚开始就是1和2相互消耗(内斗),最后剩下的还是3。

参考

算法设计:寻找多数元素
[LeetCode] 169. Majority Element 求大多数
如何理解摩尔投票算法?

posted @ 2022-05-15 13:16  strongmore  阅读(132)  评论(0编辑  收藏  举报