問題描述
給定含有n個元素的多重集合S,每個元素在S中出現的次數稱為該元素的重數。多重集S中重數最大的元素稱為眾數。例如,S={1,2,2,2,3,5}。多重集S的眾數是2,其重數為3。對於給定的n個自然數組成的多重集S,計算S的眾數及其重數 。
數組實現
缺點:復雜度高
1 package cn.htu.test; 2 3 import java.util.Arrays; 4 5 public class TestZhongShu01 { 6 7 public static void main(String[] args) { 8 int[] numbers = {1, 2, 2, 2, 3, 5}; 9 10 int maxNum = Arrays.stream(numbers).max().getAsInt(); 11 //.stream()可以把Arrays對象轉換為流,然后用stream的.max()找出流的最大元素.作為整數返回getAsInt() 12 //查幫助文檔的時候要注意Array和Arrays不同 13 14 int[] count = new int[maxNum+1];//創建一個count數組,下標從0到maxNum 15 //如此一來,所有范圍的數都可以在count數組中以下標的形式找到 16 17 for(int i=0; i<numbers.length; i++){ 18 count[numbers[i]]++; 19 //將numbers數組的情況映射到count數組上去 20 } 21 22 int tmpCount = 0; 23 int tmpValue = 0; 24 25 26 for(int i=0; i<=maxNum; i++){ 27 if(count[i] > tmpCount){ 28 tmpCount = count[i]; 29 tmpValue = i;//始終記得count的下標和numbers的元素值對應 30 } 31 } 32 33 System.out.println("The number: "+tmpValue+" appeared most times: "+tmpCount); 34 } 35 }
分治法實現
1 package cn.htu.test; 2 3 import java.util.Arrays; 4 5 public class TestZhongShu01 { 6 private static int[] numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 1, 2, 2, 3, 4, 5}; 7 8 private static int leftest = 0;//數組最左邊的下標 9 private static int rightest = numbers.length-1;//數組的最右邊的下標 10 private static int left, right; 11 12 private static int count=0; 13 private static int number; 14 15 public static void main(String[] args) { 16 17 Arrays.sort(numbers);//先進行一次排序 18 19 mode(leftest, rightest);//將leftrest和rightest,數組兩端下標傳入自定義函數mode 20 21 System.out.println("The number: "+number+" appeared most times: "+count); 22 } 23 24 private static void mode(int l, int r){ 25 26 int midIndex = getMidIndex(l, r);//自定義函數getMidIndex返回中位數下標 27 split(numbers, midIndex, l, r);//傳入數組,中間下標,最左下標和最右端下標,最后函數的作用是將left和right下標移動位置,到達中位數的左邊 28 29 if(count < right-left+1){ 30 count = right-left+1;//代表最大重數,剛開始代表中位數的重數 31 number = numbers[midIndex];//代表最大重數對應的眾數,剛開始填充的是中位數 32 } 33 //下面是分治法的內核 34 //如果左邊的數目或者右邊的數目多於最大重數就進行遞歸 35 if(left-l > count) 36 mode(l, left-1); 37 if(r-right > count) 38 mode(right+1, r); 39 } 40 41 private static int getMidIndex(int l, int r){ 42 return (l+r)/2; 43 } 44 45 private static void split(int[] numbers, int midIndex, int l, int r) 46 { 47 //用left和right都指向中位數下標 48 left = midIndex; 49 right = midIndex; 50 51 while (left-1 >=l && numbers[--left] == numbers[midIndex]);//left下標一直左移除非左移的那個數不是和中位數相等 52 while (right+1<=r && numbers[++right] == numbers[midIndex]);//right下標一直右移,除非右移的那個數和中位數不相等 53 54 //循環之后的left和right下標之間的距離就是中位數的重數 55 56 if(numbers[l] != numbers[midIndex])//把left下標移到中位數左邊的那一位,如果相同那就沒必要挪動了 57 left++; 58 if(numbers[r] != numbers[midIndex]) 59 right--; 60 } 61 }