數組中一個數字出現的次數超過了數組長度的一半,找出這個數字

 

問題:數組中一個數字出現的次數超過了數組長度的一半,找出這個數字。

我這裏給出的是隻考慮了正常情況的算法,沒有考慮數組無效,以及不符合次數超過數組長度一半的情況。

思路:

(1)將數組排序(排序的原因是爲了下面方便統計出次數)

(2)排好序後,分別統計每個元素出現的次數,並對應記錄相應的元素。

(3)找出次數最多的元素。

(補充,其實排好序後不需要統計次數了,應爲這個數字出現的次數超過了數組長度的一半,那麼中間的元素必定是它,所以2,3步多於)

算法:

//這是將數組A排序,爲了簡單考慮,先用插入排序做實驗,爲了提高性能可以選擇合併排序,堆排序或者快速排序
 public static void sort(int[] a)
 {
     for(int i = 1; i < a.length; i++)  
    {
        int key = a[i];
        int j = i - 1;
        while(j >= 0 && a[j]> key)
       {
          a[j+1] = a[j];
          j--;
        }
        a[j+1] = key;
     }
 }
 //統計次數,並找出元素
 public static int find(int[] a)
 {
     sort(a);
     int m = a.length / 2 + 1; //由於有一個數字出現的次數超過了數組長度的一般,我用來統計每個數字出現次數的數組長度至多和m一樣大。可能用不了這麼大,但是不影響我統計。
    int[] b = new int[m];  //存放排好序的元素出現的次數
    for(int i = 0; i < m; i++)
         b[i] = 1;   //首先假定每個元素至少出現一次。
    int[] c = new int[m]; //c[i]表示排好序的每個元素是什麼(無重複),對應出現次數在b[i]中,也就是b[i]表示了c[i]這個元素出現的次數。
    int i,j = 0, k = 0;  //j表示c數組和b數組的下標,k用來維護k左邊的元素都是相同的,從k開始就不同於k-1這個元素。
    for(i = 1; i < a.length; i++)
    {
       if(a[i] == a[i-1])
           b[j]++;
      else
      {
          k = i;
         c[j] = a[k-1];
         j++;
      }
   }
  //找出b中最大的元素,就是出現次數最多的下標j,對應的c[j]就是出現次數最多
  int max = 0;
  for(int p = 1; p < b.length; p++)
  {
       if(b[p] > b[max])
             max = p;
  }
  return c[max];
 }


心得:我想,大家一看到這個問題基本都是和我想的差不多,如果從效率方面,上面的算法不是一個好的算法。這個問題還有別的方法,可以充分利用次數超過一半這個條件。感興趣的同學可以討論回覆。後繼我會給出更快的算法。

思路2:

爲了省去排序的時間,我們完全可以利用java集合類庫或者C++標準模板庫來統計次數和對應的元素。這裏給出用java.HashMap寫的算法。

 

public static int find(int[] a)
 {
      HashMap<Integer,Integer> h = new   HashMap<Integer,Integer>();//建立一個HashMap,key用來表示數組中出現的元素,value表示其出現的次數。

     Set<Integer> kk = h.keySet(); //首先建立一個key視圖,如果key視圖中有此元素,將其value+1,沒有則加入,並將其值設爲1。
  //有同學會考慮你這kk一開始沒有值,之後是h發生了變化,而不是kk發生了變化,這樣可以嗎?我寫了一個輸出語句驗證了得到的kk是同步的。
  for(int i = 0; i < a.length; i++)
  {
       System.out.println(kk);//驗證得到的kk是同步的。
       if(kk.contains(a[i]))
       {
           int j = h.get(a[i]);
           j = j + 1;
           h.put(a[i], j);
       }
       else
       {
           h.put(a[i], 1);
       }
  }
  //遍歷這個HashMap集,找出最大value對應的key就行。
  int maxKey = 0, maxValue = 0;
  for(Map.Entry<Integer, Integer> entry : h.entrySet())
  {
      int key = entry.getKey();
      int value = entry.getValue();
      if(value > maxValue)
      {
         maxValue = value;
         maxKey = key;
       }
  }
  return maxKey;
 }


心得:因爲我接觸實際項目不是很多,所以有的時候不會想到去用java集合類庫,只是從數組去考慮,如果題目沒有明確要求我們完全可以利用已有的工具。

思路3:

利用題目給出的條件。希望大家可以討論討論,過兩天給給出答案。

考慮條件,如果每次都刪除兩個不同的ID,則剩下的肯定是它:

public static int find(int[] a)
	{
		int ID = a[0];//這個是假設中的ID
		int count = 0;//用來統計ID的次數,如果相同就+1,如果不同就-1,
		for(int i = 0; i < a.length; i++)
		{
			if(count == 0)//說明抵消
			{
				ID = a[i];
				count++;
			}
			else
				if(ID == a[i])//相同就增加
					count++;
				else//不同就相減
					count--;
		}
		return ID;
	}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章