1. 程式人生 > >劍指Offer:數組中出現次數超過一半的數字【39】

劍指Offer:數組中出現次數超過一半的數字【39】

idt 代碼 因此 java實現 mage 數組 sta brush ati

劍指Offer:數組中出現次數超過一半的數字【39】

題目描述

  數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如,輸入一個長度為9的數組{1,2,3,2,2,2,5,4,2}。由於這個數字2在數組中出現了5次,超過數組長度的一半,因此輸出2.

解法一:基於Partition函數時間復雜度為O(n)的算法

簡要思路

  數組中有一個數字出現的次數超過了數組長度的一半。如果把這個數組排序,那麽排序之後位於數組中間的數字一定就是那個出現次數超過數組長度一半的數字。也就是說,這個數字就是統計學上的中位數。

  在隨機快排算法中,我們現在數組中隨機選擇一個數字,然後調整數組中數字的順序,使得比選中的數字小的數字都在它的左邊,比選中數字大的數字都排在它的右邊。如果選中的這個數字的小標剛好是n/2,那麽這個數字就是這個數字的中位數;如果它的下標大於n/2,那麽中位數應該位於它的左邊,我們可以接著在它的左邊部分的數組中進行查找。否則,可以在右邊中進行查找!

  大概意思是這樣的:

技術分享圖片

Java實現代碼

import java.util.Scanner;

public class PartitionDemo {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String str = input.nextLine();
        String[] arrStr =str.split(" ");
        int[] arrN = new int[arrStr.length];
        for(int i=0;i<arrStr.length;i++)
            arrN[i]= Integer.parseInt(arrStr[i]);
        System.out.println(MoreThanHalfNum(arrN,arrN.length));
    }
    //數目超過一半的數字
    public static int MoreThanHalfNum(int[] numbers,int length)
    {
        int middle = length>>1;
        int start = 0;
        int end = length-1;
        int index = partition(numbers,start,end);
        while (index!=middle)
        {
            if(index>middle) {
                end = index-1;
                index = partition(numbers,start,end);
            }
            else{
                start = index+1;
                index=partition(numbers,start,end);
            }
        }
        int result = numbers[middle];
        return result;
    }
    //劃分
    public static int partition(int[] aux,int lo,int hi)
    {
        int i=lo,j=hi+1; //左右兩個指針,分別從兩端開始
        int val = aux[lo]; //取最左邊的第一個元素為樞紐元素
        while (true)
        {
            while (aux[++i]<val)if(i==hi)break; //左指針向右找到一個大於樞紐的
            while (aux[--j]>val)if(j==lo)break; //右指針向左找到一個大於樞紐的

            if(i>=j) break; //這個i>=j是很關鍵的,這表明現在已經劃分成功,即兩邊元素有序!
            exch(aux,i,j);  //i!=j,表示還有能找的!
        }
        exch(aux,lo,j); //把樞紐元素交換至它應該的位置!
        return j; //把劃分點返回區,目的是說,從這裏開始,兩邊分別已成為為左右子序列,返回的是j這是很關鍵的,因為i可能大於j。
    }
    //交換
    public static void exch(int[] aux,int i,int j)
    {
        int t=aux[i];
        aux[i]=aux[j];
        aux[j]=t;
    }
}

  

劍指Offer:數組中出現次數超過一半的數字【39】