劍指leetcode—數組中出現次數超過一半的數字

題目描述:數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。

你可以假設數組是非空的,並且給定的數組總是存在多數元素。

示例 1:
輸入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
輸出: 2

限制:
1 <= 數組長度 <= 50000

這道題目有多種解法

方法一:

哈希表統計法

建立哈希表統計nums中數字的數量,對應的數字爲鍵,鍵值爲數字的數量。當某一個數字的鍵值超過數組的一半長度時,該數字就是衆數。

class Solution{
    public int majorityElement(int [] nums)
    {
        HashMap<Integer,Integer> map=new HashMap<>();
        int length=nums.length/2;
        for(int i=0;i<nums.length;i++)
        {
            if(map.containsKey(nums[i]))
            {
                map.put(nums[i],map.get(nums[i])+1);
            }
            else
            {
                map.put(nums[i],1);
            }
            if(map.get(nums[i])>length)
            return nums[i];
        }
        return 0;
    }
}

方法二:

數組排序法

利用效率較高的算法排序數組,例如快速歸併排序,堆排序,然後由於衆數的數量超過數組長度的一半,所以數組中點的元素一定就是衆數,算法的時間複雜度爲O(Nlog2N)

方法三:

摩爾投票法(這方法好稀奇)

首先定義幾個概念

  • 票數和:由於衆數出現的次數超過數組長度的一半;若記衆數的票數爲+1,非衆數的票數爲-1,則一定有所有數字的票數和大於0
  • 票數抵消:設置nums中的衆數爲x,數組長度爲n,若nums的前a個數字的票數和爲0,則數組後面n-a個數字的票數和一定大於0,也就是說後面n-a個數字中的衆數還是x。

算法原理:

  • 爲構建正負抵消,假設數組中的首個元素n是衆數,遍歷統計票數,當發生正負抵消時,剩餘數組的衆數一定不變,因爲(設置真正的衆數爲x)

    • 當n==x:抵消的所有數字中,有一半是衆數
    • 當n!=x,抵消的所有數字中,少於等於一半是衆數
  • 每輪假設都可以縮小剩餘數組的區間,遍歷結束,最後一輪假設的數字就是衆數。衆數超過一半,最後一輪的票數和必定爲正數

在這裏插入圖片描述

class Solution{
	public int majorityElement(int [] nums){
	int x=0,votes=0;
	for(int num:nums){
	if(votes==0)
	x=num;
	votes+=num==x? 1:-1;
	}
	return x;
	}
}	
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章