1. 程式人生 > >求非負元素陣列所有元素能組合的最大字串

求非負元素陣列所有元素能組合的最大字串

首發於 樊浩柏科學院

問題敘述:將一個非負元素陣列中的所有元素排列組合在一起,找出值最大的那個排列情況。例如 [0, 9, 523, 94, 10, 4],排列組合後值最大數為:9945234100。

本文廢話較多,可以直接跳轉到 編碼實現 部分。

背景描述

這是我遇到的一道筆試題。首次遇見我也是很懵,當時我的第一感覺就是排序,但是沒有及時理清裡面的規律,導致後面並沒有解答出此題。

問題分析

確定輸入值

該問題描述很簡單,也給出了測試用例,需求很明白。但是還需要注意問題背後隱藏的一些問題。

可確定輸入的情況大致為:

  • 陣列元素都為非負數,但可能為 0;
  • 陣列長度並沒有確定,長度可能很大。這裡假設操作不溢位;
  • 陣列元素的位數不確定,用例只涉及到 2 位數,需要考慮多位數的情況。這裡假設操作不溢位;

尋找規律

面試時請教了一下面試官,面試官的思路:

最簡單辦法就是列舉所有可能的排列組合情況,然後求排列組合後的最大值;再就是尋找組合的規律,滿足什麼條件的元素排列在前。

當然這只是面試官提供的一些解決思路,付諸於實踐還需要探索。在複試前的一天晚上我再次翻出這個問題,並找到了一些思路。

就拿問題中的用例 [0, 9, 523, 94, 10, 4] 來說,需要找出的結果為:9,94,523,4,10,0(為了方便說明,用”,“分割了陣列元素)。

先將複雜問題簡單化處理,首先嚐試使用 排序演算法 來分析過程。分析 9 和 94 的排列,為什麼 9 排列在 94 前?[那是因為這 2 個數存在 2 種排列情況,既_ 9_94_ 和_ 9_49_,很明顯 9_94 排列大於 9_49 排列,所以需要將 9 排列在 94 前,反之則需要交換元素位置]()。如果採用這樣規則處理,是在 2 個元素之間進行列舉排列情況,且單次列舉情況限定在了 2 種,降低了問題的複雜程度並易於編碼實現,後續可以直接使用排序方法來多次重複這種 2 個元素之間的單次列舉動作。

說明:符號“_”為佔位符,表示該位置可能還存在其他元素,但不影響當前兩個元素的前後排列順序。後續出現該符號將不再說明。

總之,我認為該問題是排序問題的一個變種情況,同排序問題不同的是 比較規則。這裡不是直接比較 2 個元素值大小,而是比較 2 個元素排列組合後值的大小。

實現思路

經過上述分析,問題規律已經掌握清楚,這裡整理出實現的思路。

整體思路

  • 確定使用排序演算法實現;
  • 與傳統排序不同之處為元素之間的比較規則;

排序過程

使用氣泡排序來說明上述用例的排序過程。

比較規則

本問題的排序比較規則可以描述為:假設參與比較的兩個元素為 A、B(初始時 A 在 B 前,排序結果從左至右為由大到小),比較時如果排列 A_B 小於排列 _B_A_,A 和 B 則交換位置,反之不交換。

編碼實現

比較規則

/**
 * 比較規則
 * @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   待排序陣列
 * @return  array
 */
function bubble_sort(array $Arr) {
    $length = count($Arr);
    if ($length < 2) {
        return $Arr;
    }
for ($i = 1, $change = true; $i &lt;= $length &amp;&amp; $change; $i++) {
    $change = false;
    for ($j = $length - 1; $j &gt; $i - 1; $j--) {
        if (cmp($Arr[$j - 1], $Arr[$j]) &gt; 0) {
            $temp = $Arr[$j - 1];
            $Arr[$j - 1] = $Arr[$j];
            $Arr[$j] = $temp;
            $change = true;
        }
    }
}
return $Arr;

}

/**

  • 尋找非零元素陣列中所有元素排列組合後的最大值
  • @param array $Arr 待排序陣列
  • @param string $method 排序方法
  • @return mixed
    */
    function array_form_max_str(array $Arr, KaTeX parse error: Expected '}', got 'EOF' at end of input: … if (!is_array(Arr)) return false;
    foreach ($Arr as KaTeX parse error: Expected '}', got 'EOF' at end of input: …ue) { if (value < 0) return false;
    }
    //排序演算法
    switch (KaTeX parse error: Expected '}', got 'EOF' at end of input: … usort(Arr, “cmp”); //快速排序
    break;
    case ‘bubble’ :
    A r r = b u b b l e s o r t ( Arr = bubble_sort( Arr); //氣泡排序
    break;
    default : break;
    }
    //拼接
    return implode(’’, $Arr);
    }

<h3>快速排序</h3>
<p>由於 PHP 中 sort 排序函式採用快速排序演算法,這裡直接使用之。</p>
<pre><code class="PHP">/**
 * 尋找非零元素陣列中所有元素排列組合後的最大值
 * @param   array     $Arr        待排序陣列
 * @param   string    $method     排序方法
 * @return  mixed
 */
function array_form_max_str(array $Arr, $method = 'quick') {
    //引數校驗
    if (!is_array($Arr)) return false;
    foreach ($Arr as $value) {
        if ($value &lt; 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 = [20,913,223,91,20,3];
echo '陣列為[', implode(',', $Arr), ']', PHP_EOL;
echo '最大排列組合為:', array_form_max_str($Arr), PHP_EOL;
```

測試結果

//第1組用例
陣列為[0,9,523,94,10,4]
最大排列組合為:9945234100

//第2組用例
陣列為[20,913,223,91,20,3]
最大排列組合為:9191332232020


<h2>寫在最後</h2>
<p>經過深入分析問題的本質,也使得我對與排序演算法有了更深入的認識,更算是一個鞏固。同時,正是由於我嘗試著去解決這個問題,才使得我在後面的複試環節中面試官再次提出相同問題時,給出了一個滿意的解決方案。</p>
<p><strong>相關文章 <a href="#">»</a></strong></p>
<ul><li>
<a href="https://www.fanhaobai.com/2017/12/2017-ziroom-king-1.html#%E9%A2%983" rel="nofollow noreferrer">王者程式設計大賽之一</a>(2017-12-05)</li></ul>
原文地址:https://segmentfault.com/a/1190000017246517