1. 程式人生 > >解題筆記(25)——把陣列排成最小的數

解題筆記(25)——把陣列排成最小的數

      問題描述:輸入一個正整數陣列,將它們連線起來排成一個數,輸出能排出的所有數字中最小的一個。例如輸入陣列{32,  321},則輸出這兩個能排成的最小數字32132。請給出解決問題的演算法,並證明該演算法。

      思路:先將整數陣列轉為字串陣列,然後字串陣列進行排序,最後依次輸出字串陣列即可。這裡注意的是字串的比較函式需要重新定義,不是比較a和b,而是比較ab與 ba。如果ab < ba,則a < b;如果ab > ba,則a > b;如果ab = ba,則a = b。比較函式的定義是本解決方案的關鍵。

      證明:為什麼這樣排個序就可以了呢?簡單證明一下。根據演算法,如果a < b,那麼a排在b前面,否則

b排在a前面。可利用反證法,假設排成的最小數字為xxxxxx,並且至少存在一對字串滿足這個關係:a > b,但是在組成的數字中a排在b前面。根據a和b出現的位置,分三種情況考慮:

      (1)xxxxab,用ba代替ab可以得到xxxxba,這個數字是小於xxxxab,與假設矛盾。因此排成的最小數字中,不存在上述假設的關係。

      (2)abxxxx,用ba代替ab可以得到baxxxx,這個數字是小於abxxxx,與假設矛盾。因此排成的最小數字中,不存在上述假設的關係。

      (3)axxxxb,這一步證明麻煩了一點。可以將中間部分看成一個整體ayb,則有ay < ya,yb < by成立。將ay和by表示成10進位制數字形式,則有下述關係式,這裡a,y,b的位數分別為n,m,k。

        關係1: ay < ya => a * 10^m + y < y * 10^n + a => a * 10^m - a < y * 10^n - y => a( 10^m - 1)/( 10^n - 1) < y

        關係2: yb < by => y * 10^k + b < b * 10^m + y => y * 10^k - y < b * 10^m - b => y < b( 10^m -1)/( 10^k -1) 

        關係3: a( 10^m - 1)/( 10^n - 1) < y < b( 10^m -1)/( 10^k -1)  => a/( 10^n - 1)< b/( 10^k -1) => a*10^k - a < b * 10^n - b =>a*10^k + b < b * 10^n + a => a < b

       這與假設a > b矛盾。因此排成的最小數字中,不存在上述假設的關係。

       綜上所述,得出假設不成立,從而得出結論:對於排成的最小數字,不存在滿足下述關係的一對字串:a > b,但是在組成的數字中a出現在b的前面。從而得出演算法是正確的。

      參考程式碼:

//重新定義比較函式物件
struct compare
{
	bool operator() (const string &src1, const string &src2)
	{
		string s1 = src1 + src2;
		string s2 = src2 + src1;
		return s1 < s2;   //升序排列,如果改為s1 > s2則為逆序排列
	}
};
//函式功能 : 把陣列排成最小的數
//函式引數 : pArray為陣列,num為陣列元素個數  
//返回值 :   無
void ComArrayMin(int *pArray, int num)
{
	int i;
	string *pStrArray = new string[num];

	for(i = 0; i < num; i++) //將數字轉換為字串
	{	
		stringstream stream;
		stream<<pArray[i];
		stream>>pStrArray[i];
	}

	sort(pStrArray, pStrArray + num, compare()); //字串陣列排序

	for(i = 0; i < num; i++) //列印字串陣列
		cout<<pStrArray[i];
	cout<<endl;

	delete [] pStrArray;
}