原文:https://www.fanhaobai.com/2017/04/array-form-max-string.html
問題敘述:將一個非負(fù)元素數(shù)組中的所有元素排列組合在一起嗡呼,找出值最大的那個排列情況岳颇。例如 [0, 9, 523, 94, 10, 4]议经,排列組合后值最大數(shù)為:9945234100忍捡。
本文廢話較多简珠,可以直接跳轉(zhuǎn)到 編碼實現(xiàn) 部分担敌。
背景描述
這是我遇到的一道筆試題崎淳。首次遇見我也是很懵扔亥,當(dāng)時我的第一感覺就是排序斜做,但是沒有及時理清里面的規(guī)律苞氮,導(dǎo)致后面并沒有解答出此題。
問題分析
確定輸入值
該問題描述很簡單瓤逼,也給出了測試用例笼吟,需求很明白库物。但是還需要注意問題背后隱藏的一些問題。
可確定輸入的情況大致為:
- 數(shù)組元素都為非負(fù)數(shù)贷帮,但可能為 0戚揭;
- 數(shù)組長度并沒有確定,長度可能很大撵枢。這里假設(shè)操作不溢出民晒;
- 數(shù)組元素的位數(shù)不確定,用例只涉及到 2 位數(shù)锄禽,需要考慮多位數(shù)的情況潜必。這里假設(shè)操作不溢出;
尋找規(guī)律
面試時請教了一下面試官沃但,面試官的思路:
最簡單辦法就是枚舉所有可能的排列組合情況磁滚,然后求排列組合后的最大值;再就是尋找組合的規(guī)律宵晚,滿足什么條件的元素排列在前垂攘。
當(dāng)然這只是面試官提供的一些解決思路,付諸于實踐還需要探索淤刃。在復(fù)試前的一天晚上我再次翻出這個問題晒他,并找到了一些思路。
就拿問題中的用例 [0, 9, 523, 94, 10, 4] 來說逸贾,需要找出的結(jié)果為:9,94,523,4,10,0(為了方便說明陨仅,用”,“分割了數(shù)組元素)。
先將復(fù)雜問題簡單化處理耕陷,首先嘗試使用 排序算法 來分析過程掂名。分析 9 和 94 的排列,為什么 9 排列在 94 前哟沫?那是因為這 2 個數(shù)存在 2 種排列情況饺蔑,既_ 9_94_ 和_ 9_49_,很明顯 9_94 排列大于 9_49 排列嗜诀,所以需要將 9 排列在 94 前猾警,反之則需要交換元素位置。如果采用這樣規(guī)則處理隆敢,是在 2 個元素之間進行枚舉排列情況发皿,且單次枚舉情況限定在了 2 種,降低了問題的復(fù)雜程度并易于編碼實現(xiàn)拂蝎,后續(xù)可以直接使用排序方法來多次重復(fù)這種 2 個元素之間的單次枚舉動作穴墅。
說明:符號“_”為占位符,表示該位置可能還存在其他元素,但不影響當(dāng)前兩個元素的前后排列順序玄货。后續(xù)出現(xiàn)該符號將不再說明皇钞。
總之,我認(rèn)為該問題是排序問題的一個變種情況松捉,同排序問題不同的是 比較規(guī)則夹界。這里不是直接比較 2 個元素值大小,而是比較 2 個元素排列組合后值的大小隘世。
實現(xiàn)思路
經(jīng)過上述分析可柿,問題規(guī)律已經(jīng)掌握清楚,這里整理出實現(xiàn)的思路丙者。
整體思路
- 確定使用排序算法實現(xiàn)复斥;
- 與傳統(tǒng)排序不同之處為元素之間的比較規(guī)則;
排序過程
使用冒泡排序來說明上述用例的排序過程蔓钟。
{% asset_img 65FD0FD202413415D266AC754A75AAF3.png %}
比較規(guī)則
本問題的排序比較規(guī)則可以描述為:假設(shè)參與比較的兩個元素為 A永票、B(初始時 A 在 B 前,排序結(jié)果從左至右為由大到欣哪),比較時如果排列 A_B 小于排列 B_A键俱,A 和 B 則交換位置兰绣,反之不交換。
編碼實現(xiàn)
比較規(guī)則
/**
* 比較規(guī)則
* @param string $a
* @param string $b
* @return int
*/
function cmp($a, $b) {
if ($a == $b) {
return 0;
}
return $a . $b > $b . $a ? -1 : 1;
}
冒泡排序
/**
* 冒泡排序
* @param array $Arr 待排序數(shù)組
* @return array
*/
function bubble_sort(array $Arr) {
$length = count($Arr);
for ($i = 1, $change = true; $i <= $length && $change; $i++) {
$change = false;
for ($j = $length - 1; $j > $i - 1; $j--) {
if (cmp($Arr[$j - 1], $Arr[$j]) > 0) {
$temp = $Arr[$j - 1];
$Arr[$j - 1] = $Arr[$j];
$Arr[$j] = $temp;
$change = true;
}
}
}
return $Arr;
}
/**
* 尋找非零元素數(shù)組中所有元素排列組合后的最大值
* @param array $Arr 待排序數(shù)組
* @param string $method 排序方法
* @return mixed
*/
function array_form_max_str(array $Arr, $method = 'bubble') {
//參數(shù)校驗
if (!is_array($Arr)) return false;
foreach ($Arr as $value) {
if ($value < 0) return false;
}
//排序算法
switch ($method) {
case 'quick' :
usort($Arr, "cmp"); //快速排序
break;
case 'bubble' :
$Arr = bubble_sort($Arr); //冒泡排序
break;
default : break;
}
//拼接
return implode('', $Arr);
}
快速排序
由于 PHP 中 sort 排序函數(shù)采用快速排序算法编振,這里直接使用之缀辩。
/**
* 尋找非零元素數(shù)組中所有元素排列組合后的最大值
* @param array $Arr 待排序數(shù)組
* @param string $method 排序方法
* @return mixed
*/
function array_form_max_str(array $Arr, $method = 'quick') {
//參數(shù)校驗
if (!is_array($Arr)) return false;
foreach ($Arr as $value) {
if ($value < 0) return false;
}
//排序算法
switch ($method) {
case 'quick' : //快速排序
usort($Arr, "cmp");
break;
case 'bubble' :
$Arr = bubble_sort($Arr); //冒泡排序
break;
default : break;
}
//拼接
return implode('', $Arr);
}
用例測試
這里只對快速排序方法使用 2 組測試用例并列舉如下。
測試代碼
$Arr = [];
echo '數(shù)組為[', implode(',', $Arr), ']', PHP_EOL;
echo '最大排列組合為:', array_form_max_str($Arr), PHP_EOL;
測試結(jié)果
//第1組用例
數(shù)組為[0,9,523,94,10,4]
最大排列組合為:9945234100
//第2組用例
數(shù)組為[20,913,223,91,20,3]
最大排列組合為:9191332232020
寫在最后
經(jīng)過深入分析問題的本質(zhì)踪央,也使得我對與排序算法有了更深入的認(rèn)識臀玄,更算是一個鞏固。同時畅蹂,正是由于我嘗試著去解決這個問題健无,才使得我在后面的復(fù)試環(huán)節(jié)中面試官再次提出相同問題時,給出了一個滿意的解決方案液斜。