分析:這是09
年6這道題其實是希望我們能找到乙個排序規則,根據這個規則排出來的陣列能排成乙個最小的數字。要確定排序規則,就得比較兩個數字,也就是給出兩個數字m
和n,我們需要確定乙個規則m
和n哪個更大,而不是僅僅只是比較這兩個數字的數值哪個更大。
根據題目的要求,兩個數字m
和n排成的數字mn
和nm,如果mn,那麼我們應該輸出mn
,也就是m
應該排在n
的前面,也就是m
小於n;反之,如果nm,n
小於m。如果mn==mn
,m等於n
。接下來我們考慮怎麼去拼接數字,即給出數字m
和n,怎麼得到數字mn
和nm並比較它們的大小。直接用數值去計算不難辦到,但需要考慮到的乙個潛在問題是m
和n都在int
能表達的範圍內,但把它們拼起來的數字mn
和nm就不一定能用int
表示了。所以我們需要解決大數問題。乙個非常直觀的方法就是把數字轉換成字串。
另外,由於把數字m
和n拼接起來得到的mn
和nm,它們所含有的數字的個數肯定是相同的。因此比較它們的大小只需要按照字串大小的比較規則就可以了。
基於這個思路,我們可以寫出下面的**:
// maxinum int number has 10 digits in decimal system
const
int g_maxnumberlength = 10;
// string buffers to combine two numbers
char
* g_strcombine1 = new char[g_maxnumberlength * 2 + 1];
char
* g_strcombine2 = new char[g_maxnumberlength * 2 + 1];
// given an array, print the minimum number
// by combining all numbers in the array
void
printminnumber(int* numbers, int length)
// sort all strings according to algorithm in function compare
qsort(strnumbers, length, sizeof(char*), compare);
for(int i = 0; i < length; ++i)
printf("%s", strnumbers[i]);
printf("/n");
for(int i = 0; i < length; ++i)
delete strnumbers[i];
delete strnumbers; }
// compare two numbers in strnumber1 and strnumber2
// if [strnumber1][strnumber2] > [strnumber2][strnumber1],
// return value > 0
// if [strnumber1][strnumber2] = [strnumber2][strnumber1],
// return value = 0
// if [strnumber1][strnumber2] < [strnumber2][strnumber1],
// return value < 0
intcompare(const void* strnumber1, const void* strnumber2)
上述**中,我們在函式compare
中定義比較規則,並根據該規則用庫函式qsort
排序。最後把排好序的陣列輸出,就得到了根據陣列排成的最小的數字。
找到乙個演算法解決這個問題,不是一件容易的事情。但更困難的是我們需要證明這個演算法是正確的。接下來我們來試著證明。
首先我們需要證明之前定義的比較兩個數字大小的規則是有效的。乙個有效的比較需要三個條件:1.
自反性,即a等於
a;2.對稱性,即如果a大於
b,則b小於
a;3.傳遞性,即如果a小於
b,b小於
c,則a小於
c。現在分別予以證明。
1.自反性。顯然有
aa=aa
,所以a=a。2.
對稱性。如果a小於
b,則ab,所以
ba>ab
。因此b大於a
。 3.傳遞性。如果a小於
b,則ab。當a和
b用十進位制表示的時候分別為l位和
m位時,
ab=a
×10m+b
,ba=b
×10l+a
。所以a
×10m+b×
10l+a
。於是有a×
10m-a< b
×10l –b
,即a(10m -1)l -1)
。所以a/(10l -1)m -1)。
如果b小於c
,則bc。當
c表示成十進位制時為
m位。和前面證明過程一樣,可以得到
b/(10m -1)n -1)。
所以a/(10l -1)< c/(10n -1)
。於是a(10n -1)l -1)
,所以a
×10n +c×
10l +a
,即ac。
所以a小於c
。 在證明了我們排序規則的有效性之後,我們接著證明演算法的正確性。我們用反證法來證明。
我們把n
個數按照前面的排序規則排好順序之後,表示為
a1a2a3…an
。我們假設這樣排出來的兩個數並不是最小的。即至少存在兩個x和
y(0),交換第
x個數和地
y個數後,
a1a2…ay…ax…an
1a2…ax…ay…an。
由於a1a2…ax…ay…an
是按照前面的規則排好的序列,所以有
axx+1
x+2<…y-2
y-1y。
由於ay-1小於ay
,所以ay-1ay
yay-1
。我們在序列
a1a2…ax…ay-1ay…an
交換ay-1和ay
,有a1a2…ax…ay-1ay…an
1a2…ax…ayay-1…an
(這個實際上也需要證明。感興趣的讀者可以自己試著證明)。我們就這樣一直把
ay和前面的數字交換,直到和
ax交換為止。於是就有
a1a2…ax…ay-1ay…an
1a2…ax…ayay-1…an
< a1a2…ax…ayay-2ay-1…an
<…< a1a2…ayax…ay-2ay-1…an。
同理由於ax小於ax+1
,所以axax+1
x+1ax
。我們在序列
a1a2…ayaxax+1…ay-2ay-1…an
僅僅只交換ax和
ax+1
,有a1a2…ayaxax+1…ay-2ay-1…an
1a2…ayax+1ax…ay-2ay-1…an
。我們接下來一直拿
ax和它後面的數字交換,直到和
ay-1
交換為止。於是就有
a1a2…ayaxax+1…ay-2ay-1…an
1a2…ayax+1ax…ay-2ay-1…an
<…< a1a2…ayax+1ax+2…ay-2ay-1ax…an。
所以a1a2…ax…ay…an
< a1a2…ay…ax…an
。這和我們的假設的
a1a2…ay…ax…an
1a2…ax…ay…an
相矛盾。
所以假設不成立,我們的演算法是正確的。
把陣列排成最小的數
問題描述 輸入乙個正整數陣列,將它們連線起來排成乙個數,輸出能排出的所有數字中最小的乙個。例如輸入陣列,則輸出這兩個能排成的最小數字32132。請給出解決問題的演算法,並證明該演算法。思路 先將整數陣列轉為字串陣列,然後字串陣列進行排序,最後依次輸出字串陣列即可。這裡注意的是字串的比較函式需要重新定...
把陣列排成最小的數
題目描述 輸入乙個正整數陣列,把陣列裡所有數字拼接起來排成乙個數,列印能拼接出的所有數字中最小的乙個。例如輸入陣列,則列印出這三個數字能排成的最小數字為321323。解答 把陣列轉換成字串,再排個序,從小到大輸出就是最小的數了。include include include includeusing...
把陣列排成最小的數
題目 輸入乙個正整數陣列,把陣列裡所有數字拼接起來排成乙個數,列印能拼接處的所有數字中最小的乙個。例如輸入陣列,則列印出這3個數字能排成的最小數字321323.對於這道題,結合資料我寫的程式思路 將陣列中每個元素變成字串來處理,那麼字串的大小順序就是這個最小數字的組合順序。在字串中的比較函式comp...