把陣列排成最小的數

2021-08-26 11:16:07 字數 3330 閱讀 4722

輸入乙個正整數陣列,將它們連線起來排成乙個數,輸出能排出的所有數字中最小的乙個。例如輸入陣列

,則輸出這兩個能排成的最小數字

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...