1. 程式人生 > 其它 >在一個數組中尋找多數元素

在一個數組中尋找多數元素

問題描述

多數元素是指出現次數大於陣列總長度一半的元素,如陣列[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 求大多數
如何理解摩爾投票演算法?