把陣列排成最小的數

2021-05-25 03:29:29 字數 3958 閱讀 3908

分析:這是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...