問題:數組中一個數字出現的次數超過了數組長度的一半,找出這個數字。
我這裏給出的是隻考慮了正常情況的算法,沒有考慮數組無效,以及不符合次數超過數組長度一半的情況。
思路:
(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;
}