輸入乙個正整數陣列,將它們連線起來排成乙個數,輸出能排出的所有數字中最小的乙個。例如輸入陣列
,則輸出這兩個能排成的最小數字
32132
。請給出解決問題的演算法,並證明該演算法。
分析:這是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 decimalsystem
const
intg_maxnumberlength = 10;
// string buffers to combine two numbers
char
*g_strcombine1 =
newchar
[g_maxnumberlength * 2 + 1];
char
*g_strcombine2 =
newchar
[g_maxnumberlength * 2 + 1];
// given an array, print the minimum number
// by combining all numbers in the array
void
printminnumber(
int* numbers,
intlength)
// sort all strings according to algorithm infunction compare
qsort(strnumbers, length,
sizeof
(char
*), compare);
for(int
i = 0; i < length;++i)
printf(
"%s"
,strnumbers[i]);
printf(
"\n");
for(
inti = 0; i < length;++i)
delete
strnumbers[i];
delete
strnumbers; }
// compare two numbers in strnumber1 andstrnumber2
// 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。現在分別予以證明。
自反性。顯然有aa=aa,所以a=a。
對稱性。如果a小於b,則ab,所以ba>ab。因此b大於a。
傳遞性。如果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)。所以a/(10l -1)。
如果b小於c,則bc。當c表示成十進位制時為m位。和前面證明過程一樣,可以得到b/(10m-1)。
所以a/(10l-1)< c/(10n -1)。於是a(10n -1),所以a×10n +c×10l +a,即ac。
所以a小於c。
在證明了我們排序規則的有效性之後,我們接著證明演算法的正確性。我們用反證法來證明。
我們把n個數按照前面的排序規則排好順序之後,表示為a1a2a3…an。我們假設這樣排出來的兩個數並不是最小的。即至少存在兩個x和y(0),交換第x個數和地y個數後,a1a2…ay…ax…an。
由於a1a2…ax…ay…an是按照前面的規則排好的序列,所以有ax。
由於ay-1小於ay,所以ay-1ay。我們在序列a1a2…ax…ay-1ay…an交換ay-1和ay,有a1a2…ax…ay-1ay…an(這個實際上也需要證明。感興趣的讀者可以自己試著證明)。我們就這樣一直把ay和前面的數字交換,直到和ax交換為止。於是就有a1a2…ax…ay-1ay…an。
同理由於ax小於ax+1,所以axax+1。我們在序列a1a2…ayaxax+1…ay-2ay-1…an僅僅只交換ax和ax+1,有a1a2…ayaxax+1…ay-2ay-1…an。我們接下來一直拿ax和它後面的數字交換,直到和ay-1交換為止。於是就有a1a2…ayaxax+1…ay-2ay-1…an。
所以a1a2…ax…ay…an。這和我們的假設的a1a2…ay…ax…an 相矛盾。
所以假設不成立,我們的演算法是正確的。
把陣列排成最小的數
分析 這是09 年6這道題其實是希望我們能找到乙個排序規則,根據這個規則排出來的陣列能排成乙個最小的數字。要確定排序規則,就得比較兩個數字,也就是給出兩個數字m 和n,我們需要確定乙個規則m 和n哪個更大,而不是僅僅只是比較這兩個數字的數值哪個更大。根據題目的要求,兩個數字m 和n排成的數字mn 和...
把陣列排成最小的數
問題描述 輸入乙個正整數陣列,將它們連線起來排成乙個數,輸出能排出的所有數字中最小的乙個。例如輸入陣列,則輸出這兩個能排成的最小數字32132。請給出解決問題的演算法,並證明該演算法。思路 先將整數陣列轉為字串陣列,然後字串陣列進行排序,最後依次輸出字串陣列即可。這裡注意的是字串的比較函式需要重新定...
把陣列排成最小的數
題目描述 輸入乙個正整數陣列,把陣列裡所有數字拼接起來排成乙個數,列印能拼接出的所有數字中最小的乙個。例如輸入陣列,則列印出這三個數字能排成的最小數字為321323。解答 把陣列轉換成字串,再排個序,從小到大輸出就是最小的數了。include include include includeusing...