壹 ❀ 引
今天的題目來自LeetCode179. 最大數,題目描述如下:
給定一組非負整數 nums,重新排列每個數的順序(每個數不可拆分)使之組成一個最大的整數。
注意:輸出結果可能非常大,所以你需要返回一個字符串而不是整數。
示例 1:
輸入:nums = [10,2] 輸出:"210"
示例 2:
輸入:nums = [3,30,34,5,9] 輸出:"9534330"
示例 3:
輸入:nums = [1] 輸出:"1"
示例 4:
輸入:nums = [10] 輸出:"10"
提示:
- 1 <= nums.length <= 100
- 0 <= nums[i] <= 109
讓我們簡單分析題目,然后開始實現它。
貳 ❀ 題解與分析
其實通過第一個例子,題意就很清晰了,10和2一共就2種組合方式,由於210大於102,所以最終返回210。所以直觀的做法就是將兩個數字轉為字符串,不然數字類型2+10=12
不可能是210。假設有x,y兩個數字,通過轉為字符串,我們只需比較x+y
與y+x
的大小,便可作為排序的規則。
具體如何比較呢?如果讓你做數組排序,可能首先想到的是通過sort方法,比如:
//升序
[1, 0, 2, 5].sort((a, b) => a - b); //[0,1,2,5]
//降序
[1, 0, 2, 5].sort((a, b) => b - a); //[5,2,1,0]
我在JS 數組常見操作匯總,數組去重、降維、排序、多數組合並實現思路整理一文中,在數組排序部分對於sort做過簡單介紹,這里我們簡單復習下。
其實,sort中callback回調中參與計算的a與b我們是可以自定義的,且它們的計算結果滿足一個規則。不管是a-b
還是b-a
,它可以返回的結果分三種情況,小於0,等於0或者大於0。當結果為負數,a排在b的前面,當結果等於0,兩者順序不變,當結果為正數,那么b在a前面。覺得比較混亂的,建議找個簡單的數組理一理,比如[5,4]。算了,還是我幫你們理一理。
以數組[5,4]
,先看a-b
的情況(雖然看起來很荒謬,但是sort確實反着取數的):
[5,4].sort((a,b) => a - b);//a是4,b是5
//因為a-b是負數,所以a在b前面,所以4在5前面,得到[4,5]
我們再看b-a
的情況:
[5,4].sort((a,b) => b - a);//a是4,b是5
//因為5-4是正數,正數b在a前面,所以5在4前面,得到[5,4]
而所謂真正參與比較的a,b支持自定義,我們看個例子就懂了:
let arr = [{
name: 'echo',
age: 18
}, {
name: '聽風是風',
age: 26
}, {
name: '時間跳躍',
age: 10
}, {
name: '行星飛行',
age: 16
}];
arr.sort((a, b) => {
var a_ = a.age;
var b_ = b.age;
return a_ - b_;
});
這個例子就是按照年齡屬性對對象進行升序排列,說直白點,只要你能拿出兩個數字進行對比,sort就能按照你的期望對原數組進行排序。
而前面我們雖然將數字轉為了字符串,但本意只是希望x+y=
能組合成xy
,組合好了之后別忘了兩個數字字符串進行減法操作時,它們其實還是會還原成數字並做運算。
根據提議,因為我們期望最終數組能組合最大的數字,所以這個數組應該按降序排列,結合上面提到的sort,我們來實現這段代碼:
var largestNumber = function(nums) {
nums.sort((a, b) => {
// 組合成字符串
let S1 = a + '' + b;// 這里的S1你可以理解為a
let S2 = b + '' + a;// 這里的S2你可以理解為b
// 如果ba比ab大,b應該在a前面,按降序排列
return S2 - S1;// 這里你可以理解為b-a,如果b比a大,差為正數,那么b會排在a前面
});
// 考慮[0,0]的情況,
return nums[0] ? nums.join('') : '0';
};
如果你覺得還有點繞,可以根據注釋來理解,因為前面我們說了,a與b其實是可以進行自定義的,且排列順序是按照callback中差集的值來決定a與b的先后順序。我們期望是ba
比ab
大時,b在a前面,那自然是ba-ab
為正數才行,大概就是這么個道理。而最終有個小坑就是避免[0,0]
的情況,那么本題解析就到這里了。