1-1000放在含有1001個元素的數組中,只有唯一的一個元素值重複,其它均只出現一次。每個數組元素只能訪問一次,設計一個算法,將它找出來;不用輔助存儲空間,能否設計一個算法實現?
發起文章:算法題,求高手. 作者: 莫貝特(MBetter)
算法改進:利用異或的特性解決,找出重複數的問題,應該是目前最優算法。 作者:Ivony...
莫貝特給出的算法是:將所有數加起來,減去1+2+...+1000的和
Ivony給出的算法是: 將所有的數全部異或,得到的結果與1^2^3^...^1000的結果進行異或,得到的結果就是重複數
兩位算法的時間複雜度都是: 2n (莫貝特的算法可以用高斯算法簡化)
我把題目擴展了一下,將1000換成n,讓些題更通用一些:
1-n放在含有n+1個元素的數組中,只有唯一的一個元素值重複,其它均只出現一次。每個數組元素只能訪問一次,設計一個算法,將它找出來;不用輔助存儲空間,能否設計一個算法實現?(n可能爲奇數)(注意:數組是無序的,有序數組很好解決不討論)
下面是我的算法,先給出代碼,c#語言
/// 查找重複的數
/// </summary>
/// <param name="ints">1..n無序序列加上1..n之間的一個數</param>
/// <returns>重複的數</returns>
public static int GetRepeated(int[] array)
{
int temp = 0;
foreach (int i in array)
if (i % 2 == 1) temp += i + 1;
else temp -= i;
if (array.Length % 2 == 0) temp -= array.Length;//n爲奇數要處理一下
return temp < 0 ? -temp : temp - 1;
}
(1-2)+(3-4)+(5-6)+(7-8)+....+(n-1 - n) 等於多少?先不管,再改進一下
((1+1)-2)+((3+1)-4)+((4+1)-5)+((5+1)-6)+...+((n-1+1) - n) 等於多少?零!這個公式證明初中生都會!
這是有序序列,對無序的情況我們可以這樣理解:從數組中依次讀數,如果讀到是奇數則加上再加1,如果偶數則減去。
和代碼中的foreach對照一下吧,應該比較好理解!
函數中倒數第二行對n是奇數的情況作了些處理。
最後返回處理:
如果重複的數是偶數,則肯定被減了,則返回它的負值-temp;
如果重複的數是奇數,則肯定被加了,而且還多加了1, 返回 temp-1。
這個算法時間複雜度是n,空間複雜度是1,代碼行數是6,原理也簡單。
利用初中(小學奧賽估計也會)的知識解決一個算法問題,感覺算不上高手。只能感嘆我們以前的知識忘記了太多了!
----------------------------------------------------------------------------------------------------------
剛纔又看前面兩篇帖子的回覆,發現了loogn 提供的一個算法,本人修正了一下:
{
int temp = 0;
for (int i = 0; i < array.Length; i++)
temp += array[i] - i ;
return temp;
}
更是精簡,強人!!
不甘落後,我用lambda再改進一下:
{
return array.Select((i, j) => i - j).Sum();
}
方法三中的“i”相當與方法二中的“array[i]”;
方法三中的“j”相當於方法二中的“i”
其它大可不必寫成一個函數,像下面這樣直接調用就好了,也算是最後的極限算法了。