[劍指offer題解][Java]數組中出現次數超過一半的數字

前言

最近看了好多數據結構文章,可是數據結構拾遺系列遲遲憋不出,主要緣由是不少數據結構其實很是偏門,不只平常很難遇到,學起來還涉及不少數學模型,很難有快速的理解方法。git

本着女排「短平快」的精神,先更新下劍指offer題解系列。github

衆所周知,《劍指offer》是一本「好書」。面試

爲何這麼說?由於在面試老鳥眼裏,它裏面羅列的算法題在面試中出現的頻率是很是很是高的。有多高,以我目前很少的面試來看,在全部遇到的算法體中,本書算法題出現的機率大概是60%,也就是10道題有6題是書中原題,若是把變種題目算上,那麼這個出現機率能到達90%。算法

若是你是個算法菜雞(和我同樣),那麼最推薦的是先把劍指offer的題目搞明白。後端

對於劍指offer題解這個系列,個人寫做思路是,對於看過文章的讀者,可以作到:數組

  • 迅速瞭解該題常看法答思路(偏門思路不包括在內,節省你們時間,實在有研究需求的人能夠查閱其它資料)
  • 思路儘可能貼近原書(例如書中提到的面試官常常會要求不改變原數組,或者有空間限制等,儘可能體如今代碼中,保證讀者能夠不漏掉書中細節)
  • 儘可能精簡話語,避免冗長解釋
  • 給出代碼可運行,註釋齊全,關注細節問題

題目介紹

數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度爲9的數組{1,2,3,2,2,2,5,4,2}。因爲數字2在數組中出現了5次,超過數組長度的一半,所以輸出2。若是不存在則輸出0。安全

解題思路

方法一

思路

該方法改變了原數組。bash

首先要獲得一個推論,那就是一旦有數字大於數組的一半,那麼排序後的數組的中位數確定是這個數字,那麼咱們就先找出這個數字。微信

這種算法是受快速排序算法的啓發。在隨機快速排序算法中,咱們如今數組中隨機選擇一個數字,而後調整數組中數字的順序,使得比選中的數字小的數字都排在它的左邊,比選中的數字大的數字都排在它的右邊。若是這個選中的數字的下標恰好是n/2,那麼這個數字就是數組的中位數。若是它的下標大於n/2,那麼中位數應該位於它的左邊,咱們能夠接着在它的左邊部分的數組中查找。若是它的下標小於n/2,那麼中位數應該位於它的右邊,咱們能夠接着在它的右邊部分的數組中查找。這是一個典型的遞歸過程數據結構

找到這個數字後,再判斷他是否符合條件(大於數組的一半),由於頗有可能他是數組中出現次數最多的,可是未必大於數組的一半。

詳細細節見代碼註釋。

代碼

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        if(array.length<=0) {
            return 0;
        }

        int start = 0;
        int length = array.length;
        int end  = length-1;
        // 右移1位,至關於除2,效率更高
        int middle = length>>1;
        // 當前位置
        int index = Partition(array,start,end);

        // 直到取到中位數,纔是結果
        while(index!=middle){
            if(index>middle){
                index = Partition(array,start,index-1);
            }
            else{
                index = Partition(array,index+1,end);
            }
        }
        int result = array[middle];

        // 須要統計該數字個數,必需要大於數組長度的一半才能算
        int times = 0;
        for(int i=0;i<length;i++){
            if(result==array[i]){
                times++;
            }
        }
        if(times*2 <= length){
            result = 0;
        }
        return result;
    }

    // 快排中的每次排序實現,返回的是交換後start位置,也就是index一直改變的位置
    private int Partition(int[] array,int start,int end){
        // 取平均值不必定是整數,因此必須除2取整,不能右移
        int flag = (array[start]+array[end])/2;

        while(start<end){
            while(array[end]>flag){
                end--;
            }
            swap(array,start,end);
            while(array[start]<=flag){
                start++;
            }
            swap(array,start,end);
        }
        return start;
    }
    private void swap(int[] array, int num1, int num2){
        int temp = array[num1];
        array[num1] = array[num2];
        array[num2] = temp;
    }
}
複製代碼

方法二:兩兩消除

思路

該方法不改變原數組。

若是有符合條件的數字,則它出現的次數比其餘全部數字出現的次數和還要多。 在遍歷數組時保存兩個值:

  • times:次數
  • result:當前數字

遍歷下一個數字時,若它與以前保存的數字相同,則次數加1,不然次數減1;若次數爲0,則保存下一個數字,並將次數置爲1。

遍歷結束後,所保存的數字即爲所求。

以後,還要再判斷它是否符合大於數組的一半。

詳細細節見代碼註釋。

代碼

public int MoreThanHalfNum_Solution(int [] array) {
    int length = array.length;
    
    // 檢測數組是否爲空
    if (length == 0){
        return 0;
    }
    
    // 初始化result和times參數
    int result = array[0];
    int times = 1;
    
    //遍歷數組(因爲初始化過,因此直接從第二個數字開始)
    for(int i=1;i<length;i++){
        // 次數爲0時寫入下一個數字並將次數置1
        if(times == 0){
            result = array[i];
            times = 1;
        }
        // 數字相同,加1
        else if(array[i] == result){
            times++;
        }
        // 數字不一樣,減1
        else{
            times--;
        }
    }
    
    // 須要統計該數字個數,必需要大於數組長度的一半才能算
    times = 0;
    for(int i=0;i<length;i++){
        if(result==array[i]){
            times++;
        }
   }
    if(times*2 <= length){
       result = 0;
   }
    
   return result;
}
複製代碼

方法三:hashmap

思路

將數組中的數字依次遍歷,並寫入hashmap中,hashmap的值是該數字出現的次數,並在每次循環中判斷是否該數次數大於數組的一半,如有直接返回數字,不然遍歷完數組返回0。

代碼

思路簡單,代碼略。

總結

三種方法時間複雜度都是O(n)

關注我

我是一名後端開發。主要關注後端開發,數據安全,爬蟲等方向。微信:yangzd1102

Github:@qqxx6661

我的博客:

原創博客主要內容

  • Java知識點複習全手冊
  • Leetcode算法題解析
  • 劍指offer算法題解析
  • SpringCloud菜鳥入門實戰系列
  • SpringBoot菜鳥入門實戰系列
  • Python爬蟲相關技術文章
  • 後端開發相關技術文章

我的公衆號:Rude3Knife

我的公衆號:Rude3Knife

若是文章對你有幫助,不妨收藏起來並轉發給您的朋友們~

相關文章
相關標籤/搜索