題目描述:
給定一組非負整數,重新排列它們的順序使之組成一個最大的整數。
示例 1:
輸入: [10,2] 輸出: 210
示例 2:
輸入: [3,30,34,5,9] 輸出: 9534330
說明: 輸出結果可能非常大,所以你需要返回一個字符串而不是整數。
要完成的函數:
string largestNumber(vector<int>& nums)
說明:
1、這道題給定一個vector,裏面存放着int類型的非負整數,要求把這些非負整數拼起來,儘可能拼成一個最大的整數。
比如[10,2],可以拼成102,也可以拼成210,最大的整數就是210,那麼返回210,以字符串的形式。
2、這道題關鍵在於判斷,判斷vector中的兩個數誰大誰小,誰應該放在前面。
舉個例子,比如[3,30,31,32,33,34,35,102,9,990],大家覺得應該怎麼排序?
我們要儘可能讓大的數字放在前面,所以首位肯定要放個大一點的,那麼就是9了,其餘的都是3,放在首位不合適。
那麼9有兩個,要放9還是990,這裏要對這兩個數的組合做個判斷。
一種是9990,一種是9909,所以還是9-990這種組合。
那麼接下來呢,9-990之後呢?3跟30比,一種是330,一種是303,所以還是3在30前面。
那3跟31比呢,一種是331,一種是313,還是3在31前面。
是不是所有短的數字都要放在前面?
其實不是的,比如3和34,一種是334,一種是343,還要考慮到後面這一位的情況。
所以最終排列下來,“降序”排列,是[9,990,35,34,33,3,32,31,30]。
按照這個vector從前往後添加到要返回的字符串中,就可以了。
這道題的關鍵在於判斷誰在前誰在後,比較的方法也很普通,就是補齊兩個字符串,比較誰大誰小。
當然在實際操作中,沒有必要真的對字符串補齊,我們同樣可以操作。
代碼如下:(附詳解)
static bool cmp(int &a1,int &b1)//自定義一個比較函數,大的放前面 { string a=to_string(a1),b=to_string(b1);//先把兩個整數轉化爲字符串,操作起來比較方便 int s1=a.size(),s2=b.size(); if(s1<s2)//如果a短b長 { for(int i=0;i<s1;i++)//在a的長度內比較 { if(a[i]>b[i])//如果發現a中的某一位數值已經大於b中同一位的數值,比如4和39 return true;//那麼比較到此結束,4要放在前面 else if(a[i]<b[i])//如果發現a中的某一位數值已經小於b中同一位的數值,比如4和61 return false;//那麼比較到此結束,61要放在前面 } for(int i=s1;i<s2;i++)//如果上面的比較沒出結果,比如4和456這種情況,那麼開始新的比較,直到到達第二個字符串的最後一位 { //這個循環其實比較的是4和5,5和6,到達第二個字符串的最後一位就不比較了 if(b[i-s1]>b[i])//如果滿足條件,那麼a要放在前面 return true; else if(b[i-s1]<b[i])//如果滿足條件,那麼b要放在前面 return false; } for(int i=0;i<s1;i++)//如果上面的比較沒出結果,其實我們還有最後一位沒有比較,6和4 { if(a[i]<b[s2-s1+i]) return true; else if(a[i]>b[s2-s1+i]) return false; } return false;//如果上述比較都沒出結果,比如3和333,那麼返回false,這裏隨便拼都可以 } else if(s1>s2)//如果a長b短,一樣的比較方式 { for(int i=0;i<s2;i++) { if(a[i]<b[i]) return false; else if(a[i]>b[i]) return true; } for(int i=s2;i<s1;i++) { if(a[i-s2]>a[i]) return false; else if(a[i-s2]<a[i]) return true; } for(int i=0;i<s2;i++) { if(b[i]>a[s1-s2+i]) return true; else if(b[i]<a[s1-s2+i]) return false; } return false; } else//如果兩個一樣長,那麼直接逐位比較就可以了 { for(int i=0;i<s1;i++) { if(a[i]>b[i]) return true; else if(a[i]<b[i]) return false; } return false; } } string largestNumber(vector<int>& nums) { sort(nums.begin(),nums.end(),cmp);//調用sort函數進行排序,排序準則是我們自定義的比較函數 string res; for(auto i:nums) res+=to_string(i);//不斷地插入到字符串的末尾 if(res[0]=='0')return "0";//邊界條件,如果第一位是0,那麼說明後面即使有,也是全0,這時候我們只需要返回0就可以了了,而不是一長串的0 return res; }
上述代碼實測4ms,beats 99.85% of cpp submissions。
關於cmp函數,筆者在網上看到過一個簡單的降序排列的版本,如下:
bool cmp1(int &a,int &b) { return a>b; } int main() { vector<int>nums={1,2,3,4,5,6,7,8,9,10,11,12}; sort(nums.begin(),nums.end(),cmp1); for(int i:nums) cout<<i<<" "; cout<<endl; return 0; }
上面的cmp1這個函數,筆者個人猜想其實是說,如果a>b,那麼返回true,認爲前面的數大於後面的數是正確的。
所以在進行排序的時候,如果前面的數大於後面的,那麼經過cmp1這個函數,返回true,認爲正確,所以不用更改。
如果前面的數小於後面的數,那麼經過cmp1這個函數,返回false,認爲錯誤,所以要換一下位置。
所以筆者就根據自己的猜想,設計了題解代碼中的cmp函數,從結果來看,上述認識還是有一定可取之處的。
但上述僅爲筆者個人的猜想,有可能是不完全的甚至有些錯誤,沒有仔細地去查sort函數的參數,僅作爲一個個人的認識。